2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/update/manager/prepare-render-instructions.h>
21 #include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
22 #include <dali/internal/update/resources/resource-manager-declarations.h>
23 #include <dali/internal/update/manager/sorted-layers.h>
24 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
25 #include <dali/internal/update/node-attachments/scene-graph-renderable-attachment.h>
26 #include <dali/internal/update/nodes/scene-graph-layer.h>
27 #include <dali/internal/render/common/render-item.h>
28 #include <dali/internal/render/common/render-tracker.h>
29 #include <dali/internal/render/common/render-instruction.h>
30 #include <dali/internal/render/common/render-instruction-container.h>
31 #include <dali/internal/render/renderers/scene-graph-renderer.h>
43 * Set flags for opaque renderlist
44 * @param renderList to set the flags to
45 * @param transparentRenderersExist is true if there is transparent renderers in this layer
46 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
47 * @param depthTestDisabled whether depth test is disabled.
49 inline void SetOpaqueRenderFlags( RenderList& renderList, bool transparentRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
51 // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
52 // and this renderer does not need depth test against itself (for example a mesh actor)
53 // if this layer has got exactly one opaque renderer
54 // and this renderer is not interested in depth testing
55 // (i.e. is an image or text and not a model)
56 if ( ( ( renderList.Count() == 1 ) &&
57 ( !transparentRenderersExist ) &&
58 ( !renderList.GetRenderer( 0 )->RequiresDepthTest() ) ) ||
61 // no need to enable depth test or clear depth buffer
62 // if there's something transparent already rendered by previous layers,
63 // this opaque renderer will correctly draw on top of them since no depth test
64 renderList.ClearFlags();
68 // Prepare for rendering multiple opaque objects
69 unsigned int flags = RenderList::DEPTH_TEST | RenderList::DEPTH_WRITE | RenderList::DEPTH_CLEAR; // clear depth buffer, draw over the previously rendered layers;
71 renderList.ClearFlags();
72 renderList.SetFlags(flags);
75 if( stencilRenderablesExist )
77 renderList.SetFlags( RenderList::STENCIL_TEST );
82 * Set the transparent flags on the renderlist
83 * @param renderList to set the flags on
84 * @param opaqueRenderersExist is true if there are opaque renderers on this layer
85 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
86 * @param depthTestDisabled whether depth test is disabled.
88 inline void SetTransparentRenderFlags( RenderList& renderList, bool opaqueRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
90 renderList.ClearFlags();
91 // We don't need to write to the depth buffer, as transparent objects
92 // don't obscure each other.
94 if ( opaqueRenderersExist && !depthTestDisabled )
96 // If there are a mix of opaque and transparent objects, the transparent
97 // objects should be rendered with depth test on to avoid background objects
98 // appearing in front of opaque foreground objects.
100 renderList.SetFlags( RenderList::DEPTH_TEST );
103 if( stencilRenderablesExist )
105 renderList.SetFlags( RenderList::STENCIL_TEST );
111 * Set flags for overlay renderlist
112 * @param renderList to set the flags for
113 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
115 inline void SetOverlayRenderFlags( RenderList& renderList, bool stencilRenderablesExist )
117 if(stencilRenderablesExist)
119 renderList.SetFlags(RenderList::STENCIL_TEST);
124 * Set flags for stencil renderlist
125 * @param renderList to set the flags for
127 inline void SetStencilRenderFlags( RenderList& renderList )
129 renderList.ClearFlags();
130 renderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_TEST);
134 * Add a renderer to the list
135 * @param updateBufferIndex to read the model matrix from
136 * @param renderList to add the item to
137 * @param renderable attachment
138 * @param viewMatrix used to calculate modelview matrix for the item
140 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
141 RenderList& renderList,
142 RenderableAttachment& renderable,
143 const Matrix& viewMatrix )
145 const Renderer& renderer = renderable.GetRenderer();
147 // Get the next free RenderItem
148 RenderItem& item = renderList.GetNextFreeItem();
149 item.SetRenderer( const_cast< Renderer* >( &renderer ) );
151 // calculate MV matrix onto the item
152 Matrix& modelViewMatrix = item.GetModelViewMatrix();
153 const Matrix& worldMatrix = renderable.GetParent().GetWorldMatrix( updateBufferIndex );
155 Matrix::Multiply( modelViewMatrix, worldMatrix, viewMatrix );
159 * Add all renderers to the list
160 * @param updateBufferIndex to read the model matrix from
161 * @param renderList to add the items to
162 * @param renderable attachments
163 * @param viewMatrix used to calculate modelview matrix for the items
165 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
166 RenderList& renderList,
167 RenderableAttachmentContainer& attachments,
168 const Matrix& viewMatrix )
170 // Add renderer for each attachment
171 const RenderableAttachmentIter endIter = attachments.end();
172 for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
174 RenderableAttachment& attachment = **iter;
175 AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix );
180 * Try to reuse cached renderitems from the renderlist
181 * This avoids recalculating the model view matrices in case this part of the scene was static
182 * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
183 * @param layer that is being processed
184 * @param renderList that is cached from frame N-1
185 * @param attachmentList that is being used
187 inline bool TryReuseCachedRenderers( Layer& layer,
188 RenderList& renderList,
189 RenderableAttachmentContainer& attachmentList )
191 bool retValue = false;
192 size_t renderableCount = attachmentList.size();
193 // check that the cached list originates from this layer and that the counts match
194 if( ( renderList.GetSourceLayer() == &layer )&&
195 ( renderList.GetCachedItemCount() == renderableCount ) )
197 // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
198 // Attachments are not sorted, but render list is so at this stage renderers may be in different order
199 // therefore we check a combined sum of all renderer addresses
200 size_t checkSumNew = 0;
201 size_t checkSumOld = 0;
202 for( size_t index = 0; index < renderableCount; ++index )
204 RenderableAttachment* attachment = attachmentList[ index ];
205 const Renderer& renderer = attachment->GetRenderer();
206 checkSumNew += size_t( &renderer );
207 checkSumOld += size_t( renderList.GetRenderer( index ) );
209 if( checkSumNew == checkSumOld )
211 // tell list to reuse its existing items
212 renderList.ReuseCachedItems();
220 * Add opaque renderers from the layer onto the next free render list
221 * @param updateBufferIndex to use
222 * @param layer to get the renderers from
223 * @param viewmatrix for the camera from rendertask
224 * @param transparentRenderersExist is true if there is transparent renderers in this layer
225 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
226 * @param instruction to fill in
227 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
229 inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
231 const Matrix& viewMatrix,
232 bool transparentRenderablesExist,
233 bool stencilRenderablesExist,
234 RenderInstruction& instruction,
235 bool tryReuseRenderList )
237 RenderList& opaqueRenderList = instruction.GetNextFreeRenderList( layer.opaqueRenderables.size() );
238 opaqueRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
240 // try to reuse cached renderitems from last time around
241 if( tryReuseRenderList )
243 if( TryReuseCachedRenderers( layer, opaqueRenderList, layer.opaqueRenderables ) )
245 // reset the flags as other layers might have changed
246 // opaque flags can only be set after renderers are added
247 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
251 AddRenderersToRenderList( updateBufferIndex, opaqueRenderList, layer.opaqueRenderables, viewMatrix );
253 // opaque flags can only be set after renderers are added
254 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
258 * Function which sorts based on the calculated depth values ordering them back to front
261 * @return true if left item is greater than right
263 bool SortByDepthSortValue( const RendererWithSortValue& lhs, const RendererWithSortValue& rhs )
265 return lhs.first > rhs.first;
269 * Sort transparent render items
270 * @param transparentRenderList to sort
271 * @param layer where the renderers are from
272 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
274 inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer& layer, RendererSortingHelper& sortingHelper )
276 const size_t renderableCount = transparentRenderList.Count();
277 // reserve space if needed
278 const unsigned int oldcapacity = sortingHelper.size();
279 if( oldcapacity < renderableCount )
281 sortingHelper.reserve( renderableCount );
282 // add real objects (reserve does not construct objects)
283 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
284 (renderableCount - oldcapacity),
285 RendererWithSortValue( 0.0f, NULL ) );
289 // clear extra elements from helper, does not decrease capability
290 sortingHelper.resize( renderableCount );
292 // calculate the sorting value, once per item by calling the layers sort function
293 // Using an if and two for-loops rather than if inside for as its better for branch prediction
294 if( layer.UsesDefaultSortFunction() )
296 for( size_t index = 0; index < renderableCount; ++index )
298 RenderItem& item = transparentRenderList.GetItem( index );
299 // the default sorting function should get inlined here
300 sortingHelper[ index ].first = Internal::Layer::ZValue(
301 item.GetModelViewMatrix().GetTranslation3(),
302 layer.transparentRenderables[ index ]->GetSortModifier() );
303 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
304 sortingHelper[ index ].second = &item;
309 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
310 for( size_t index = 0; index < renderableCount; ++index )
312 RenderItem& item = transparentRenderList.GetItem( index );
313 sortingHelper[ index ].first = (*sortFunction)(
314 item.GetModelViewMatrix().GetTranslation3(),
315 layer.transparentRenderables[ index ]->GetSortModifier() );
316 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
317 sortingHelper[ index ].second = &item;
321 // sort the renderers back to front, Z Axis point from near plane to far plane
322 std::sort( sortingHelper.begin(), sortingHelper.end(), SortByDepthSortValue );
324 // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
325 RenderItemContainer::Iterator renderListIter = transparentRenderList.GetContainer().Begin();
326 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
328 *renderListIter = sortingHelper[ index ].second;
333 * Add transparent renderers from the layer onto the next free render list
334 * @param updateBufferIndex to use
335 * @param layer to get the renderers from
336 * @param viewmatrix for the camera from rendertask
337 * @param opaqueRenderablesExist is true if there are opaque renderers on this layer
338 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
339 * @param instruction to fill in
340 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
341 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
343 inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
345 const Matrix& viewMatrix,
346 bool opaqueRenderablesExist,
347 bool stencilRenderablesExist,
348 RenderInstruction& instruction,
349 RendererSortingHelper& sortingHelper,
350 bool tryReuseRenderList )
352 const size_t renderableCount = layer.transparentRenderables.size();
353 RenderList& transparentRenderList = instruction.GetNextFreeRenderList( renderableCount );
354 transparentRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
355 // transparent flags are independent of the amount of transparent renderers
356 SetTransparentRenderFlags( transparentRenderList, opaqueRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
358 // try to reuse cached renderitems from last time around
359 if( tryReuseRenderList )
361 if( TryReuseCachedRenderers( layer, transparentRenderList, layer.transparentRenderables ) )
366 transparentRenderList.SetSourceLayer( &layer );
368 AddRenderersToRenderList( updateBufferIndex, transparentRenderList, layer.transparentRenderables, viewMatrix );
370 // sorting is only needed if more than 1 item
371 if( renderableCount > 1 )
373 SortTransparentRenderItems( transparentRenderList, layer, sortingHelper );
378 * Add overlay renderers from the layer onto the next free render list
379 * @param updateBufferIndex to use
380 * @param layer to get the renderers from
381 * @param viewmatrix for the camera from rendertask
382 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
383 * @param instruction to fill in
384 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
386 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
388 const Matrix& viewMatrix,
389 bool stencilRenderablesExist,
390 RenderInstruction& instruction,
391 bool tryReuseRenderList )
393 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.size() );
394 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
395 SetOverlayRenderFlags( overlayRenderList, stencilRenderablesExist );
397 // try to reuse cached renderitems from last time around
398 if( tryReuseRenderList )
400 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
405 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix );
409 * Add stencil renderers from the layer onto the next free render list
410 * @param updateBufferIndex to use
411 * @param layer to get the renderers from
412 * @param viewmatrix for the camera from rendertask
413 * @param instruction to fill in
414 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
416 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
418 const Matrix& viewMatrix,
419 RenderInstruction& instruction,
420 bool tryReuseRenderList )
422 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.size() );
423 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
424 SetStencilRenderFlags( stencilRenderList );
426 // try to reuse cached renderitems from last time around
427 if( tryReuseRenderList )
429 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
434 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix );
438 * Prepare a single render instruction
439 * @param updateBufferIndex to use
440 * @param sortedLayers to prepare the instruction from
441 * @param renderTask to get the view matrix
442 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
443 * @param renderTracker An optional render tracker object
444 * @param instructions container
446 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
447 SortedLayerPointers& sortedLayers,
448 RenderTask& renderTask,
449 RendererSortingHelper& sortingHelper,
450 RenderTracker* renderTracker,
451 RenderInstructionContainer& instructions )
453 // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
454 // then populate with instructions.
455 RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
456 renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
457 bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
459 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
461 const SortedLayersIter endIter = sortedLayers.end();
462 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
464 Layer& layer = **iter;
466 const bool stencilRenderablesExist( !layer.stencilRenderables.empty() );
467 const bool opaqueRenderablesExist( !layer.opaqueRenderables.empty() );
468 const bool transparentRenderablesExist( !layer.transparentRenderables.empty() );
469 const bool overlayRenderablesExist( !layer.overlayRenderables.empty() );
470 const bool tryReuseRenderList( layer.CanReuseRenderers() && viewMatrixHasNotChanged );
472 // Ignore stencils if there's nothing to test
473 if( stencilRenderablesExist &&
474 ( opaqueRenderablesExist || transparentRenderablesExist || overlayRenderablesExist ) )
476 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, instruction, tryReuseRenderList );
479 if ( opaqueRenderablesExist )
481 AddOpaqueRenderers( updateBufferIndex,
484 transparentRenderablesExist,
485 stencilRenderablesExist,
487 tryReuseRenderList );
490 if ( transparentRenderablesExist )
492 AddTransparentRenderers( updateBufferIndex,
495 opaqueRenderablesExist,
496 stencilRenderablesExist,
499 tryReuseRenderList );
502 if ( overlayRenderablesExist )
504 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist,
505 instruction, tryReuseRenderList );
509 instruction.mRenderTracker = renderTracker;
511 // inform the render instruction that all renderers have been added and this frame is complete
512 instruction.UpdateCompleted();