2 * Copyright (c) 2014 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/internal/event/actors/layer-impl.h> // for the default sorting function
23 #include <dali/internal/update/resources/resource-manager-declarations.h>
24 #include <dali/internal/update/manager/sorted-layers.h>
25 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
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/render/common/render-item.h>
29 #include <dali/internal/render/common/render-tracker.h>
30 #include <dali/internal/render/common/render-instruction.h>
31 #include <dali/internal/render/common/render-instruction-container.h>
32 #include <dali/internal/render/renderers/scene-graph-renderer.h>
44 * Set flags for opaque renderlist
45 * @param renderList to set the flags to
46 * @param transparentRenderersExist is true if there is transparent renderers in this layer
47 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
48 * @param depthTestDisabled whether depth test is disabled.
50 inline void SetOpaqueRenderFlags( RenderList& renderList, bool transparentRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
52 // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
53 // and this renderer does not need depth test against itself (for example a mesh actor)
54 // if this layer has got exactly one opaque renderer
55 // and this renderer is not interested in depth testing
56 // (i.e. is an image and not a model)
57 if ( ( ( renderList.Count() == 1 ) &&
58 ( !transparentRenderersExist ) &&
59 ( !renderList.GetRenderer( 0 )->RequiresDepthTest() ) ) ||
62 // no need to enable depth test or clear depth buffer
63 // if there's something transparent already rendered by previous layers,
64 // this opaque renderer will correctly draw on top of them since no depth test
65 renderList.ClearFlags();
69 // Prepare for rendering multiple opaque objects
70 unsigned int flags = RenderList::DEPTH_TEST | RenderList::DEPTH_WRITE | RenderList::DEPTH_CLEAR; // clear depth buffer, draw over the previously rendered layers;
72 renderList.ClearFlags();
73 renderList.SetFlags(flags);
76 if( stencilRenderablesExist )
78 renderList.SetFlags( RenderList::STENCIL_TEST );
83 * Set the transparent flags on the renderlist
84 * @param renderList to set the flags on
85 * @param opaqueRenderersExist is true if there are opaque renderers on this layer
86 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
87 * @param depthTestDisabled whether depth test is disabled.
89 inline void SetTransparentRenderFlags( RenderList& renderList, bool opaqueRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
91 renderList.ClearFlags();
92 // We don't need to write to the depth buffer, as transparent objects
93 // don't obscure each other.
95 if ( opaqueRenderersExist && !depthTestDisabled )
97 // If there are a mix of opaque and transparent objects, the transparent
98 // objects should be rendered with depth test on to avoid background objects
99 // appearing in front of opaque foreground objects.
101 renderList.SetFlags( RenderList::DEPTH_TEST );
104 if( stencilRenderablesExist )
106 renderList.SetFlags( RenderList::STENCIL_TEST );
112 * Set flags for overlay renderlist
113 * @param renderList to set the flags for
114 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
116 inline void SetOverlayRenderFlags( RenderList& renderList, bool stencilRenderablesExist )
118 if(stencilRenderablesExist)
120 renderList.SetFlags(RenderList::STENCIL_TEST);
125 * Set flags for stencil renderlist
126 * @param renderList to set the flags for
128 inline void SetStencilRenderFlags( RenderList& renderList )
130 renderList.ClearFlags();
131 renderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_TEST);
135 * Add a renderer to the list
136 * @param updateBufferIndex to read the model matrix from
137 * @param renderList to add the item to
138 * @param renderable attachment
139 * @param viewMatrix used to calculate modelview matrix for the item
141 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
142 RenderList& renderList,
143 RenderableAttachment& renderable,
144 const Matrix& viewMatrix )
146 const Renderer& renderer = renderable.GetRenderer();
148 // Get the next free RenderItem
149 RenderItem& item = renderList.GetNextFreeItem();
150 item.SetRenderer( const_cast< Renderer* >( &renderer ) );
152 // calculate MV matrix onto the item
153 Matrix& modelViewMatrix = item.GetModelViewMatrix();
154 const Matrix& worldMatrix = renderable.GetParent().GetWorldMatrix( updateBufferIndex );
156 Matrix::Multiply( modelViewMatrix, 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 * @param viewMatrix used to calculate modelview matrix for the items
166 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
167 RenderList& renderList,
168 RenderableAttachmentContainer& attachments,
169 const Matrix& viewMatrix )
171 // Add renderer for each attachment
172 const RenderableAttachmentIter endIter = attachments.end();
173 for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
175 RenderableAttachment& attachment = **iter;
176 AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix );
181 * Try to reuse cached renderitems from the renderlist
182 * This avoids recalculating the model view matrices in case this part of the scene was static
183 * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
184 * @param layer that is being processed
185 * @param renderList that is cached from frame N-1
186 * @param attachmentList that is being used
188 inline bool TryReuseCachedRenderers( Layer& layer,
189 RenderList& renderList,
190 RenderableAttachmentContainer& attachmentList )
192 bool retValue = false;
193 size_t renderableCount = attachmentList.size();
194 // check that the cached list originates from this layer and that the counts match
195 if( ( renderList.GetSourceLayer() == &layer )&&
196 ( renderList.GetCachedItemCount() == renderableCount ) )
198 // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
199 // Attachments are not sorted, but render list is so at this stage renderers may be in different order
200 // therefore we check a combined sum of all renderer addresses
201 size_t checkSumNew = 0;
202 size_t checkSumOld = 0;
203 for( size_t index = 0; index < renderableCount; ++index )
205 RenderableAttachment* attachment = attachmentList[ index ];
206 const Renderer& renderer = attachment->GetRenderer();
207 checkSumNew += size_t( &renderer );
208 checkSumOld += size_t( renderList.GetRenderer( index ) );
210 if( checkSumNew == checkSumOld )
212 // tell list to reuse its existing items
213 renderList.ReuseCachedItems();
221 * Add opaque renderers from the layer onto the next free render list
222 * @param updateBufferIndex to use
223 * @param layer to get the renderers from
224 * @param viewmatrix for the camera from rendertask
225 * @param transparentRenderersExist is true if there is transparent renderers in this layer
226 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
227 * @param instruction to fill in
228 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
230 inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
232 const Matrix& viewMatrix,
233 bool transparentRenderablesExist,
234 bool stencilRenderablesExist,
235 RenderInstruction& instruction,
236 bool tryReuseRenderList )
238 RenderList& opaqueRenderList = instruction.GetNextFreeRenderList( layer.opaqueRenderables.size() );
239 opaqueRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
241 // try to reuse cached renderitems from last time around
242 if( tryReuseRenderList )
244 if( TryReuseCachedRenderers( layer, opaqueRenderList, layer.opaqueRenderables ) )
246 // reset the flags as other layers might have changed
247 // opaque flags can only be set after renderers are added
248 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
252 AddRenderersToRenderList( updateBufferIndex, opaqueRenderList, layer.opaqueRenderables, viewMatrix );
254 // opaque flags can only be set after renderers are added
255 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
259 * Function which sorts based on the calculated depth values ordering them back to front
262 * @return true if left item is greater than right
264 bool SortByDepthSortValue( const RendererWithSortValue& lhs, const RendererWithSortValue& rhs )
266 return lhs.first > rhs.first;
270 * Sort transparent render items
271 * @param transparentRenderList to sort
272 * @param layer where the renderers are from
273 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
275 inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer& layer, RendererSortingHelper& sortingHelper )
277 const size_t renderableCount = transparentRenderList.Count();
278 // reserve space if needed
279 const unsigned int oldcapacity = sortingHelper.size();
280 if( oldcapacity < renderableCount )
282 sortingHelper.reserve( renderableCount );
283 // add real objects (reserve does not construct objects)
284 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
285 (renderableCount - oldcapacity),
286 RendererWithSortValue( 0.0f, NULL ) );
290 // clear extra elements from helper, does not decrease capability
291 sortingHelper.resize( renderableCount );
293 // calculate the sorting value, once per item by calling the layers sort function
294 // Using an if and two for-loops rather than if inside for as its better for branch prediction
295 if( layer.UsesDefaultSortFunction() )
297 for( size_t index = 0; index < renderableCount; ++index )
299 RenderItem& item = transparentRenderList.GetItem( index );
300 // the default sorting function should get inlined here
301 sortingHelper[ index ].first = Internal::Layer::ZValue(
302 item.GetModelViewMatrix().GetTranslation3(),
303 layer.transparentRenderables[ index ]->GetSortModifier() );
304 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
305 sortingHelper[ index ].second = &item;
310 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
311 for( size_t index = 0; index < renderableCount; ++index )
313 RenderItem& item = transparentRenderList.GetItem( index );
314 sortingHelper[ index ].first = (*sortFunction)(
315 item.GetModelViewMatrix().GetTranslation3(),
316 layer.transparentRenderables[ index ]->GetSortModifier() );
317 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
318 sortingHelper[ index ].second = &item;
322 // sort the renderers back to front, Z Axis point from near plane to far plane
323 std::sort( sortingHelper.begin(), sortingHelper.end(), SortByDepthSortValue );
325 // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
326 RenderItemContainer::Iterator renderListIter = transparentRenderList.GetContainer().Begin();
327 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
329 *renderListIter = sortingHelper[ index ].second;
334 * Add transparent renderers from the layer onto the next free render list
335 * @param updateBufferIndex to use
336 * @param layer to get the renderers from
337 * @param viewmatrix for the camera from rendertask
338 * @param opaqueRenderablesExist is true if there are opaque renderers on this layer
339 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
340 * @param instruction to fill in
341 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
342 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
344 inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
346 const Matrix& viewMatrix,
347 bool opaqueRenderablesExist,
348 bool stencilRenderablesExist,
349 RenderInstruction& instruction,
350 RendererSortingHelper& sortingHelper,
351 bool tryReuseRenderList )
353 const size_t renderableCount = layer.transparentRenderables.size();
354 RenderList& transparentRenderList = instruction.GetNextFreeRenderList( renderableCount );
355 transparentRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
356 // transparent flags are independent of the amount of transparent renderers
357 SetTransparentRenderFlags( transparentRenderList, opaqueRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
359 // try to reuse cached renderitems from last time around
360 if( tryReuseRenderList )
362 if( TryReuseCachedRenderers( layer, transparentRenderList, layer.transparentRenderables ) )
367 transparentRenderList.SetSourceLayer( &layer );
369 AddRenderersToRenderList( updateBufferIndex, transparentRenderList, layer.transparentRenderables, viewMatrix );
371 // sorting is only needed if more than 1 item
372 if( renderableCount > 1 )
374 SortTransparentRenderItems( transparentRenderList, layer, sortingHelper );
379 * Add overlay renderers from the layer onto the next free render list
380 * @param updateBufferIndex to use
381 * @param layer to get the renderers from
382 * @param viewmatrix for the camera from rendertask
383 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
384 * @param instruction to fill in
385 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
387 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
389 const Matrix& viewMatrix,
390 bool stencilRenderablesExist,
391 RenderInstruction& instruction,
392 bool tryReuseRenderList )
394 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.size() );
395 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
396 SetOverlayRenderFlags( overlayRenderList, stencilRenderablesExist );
398 // try to reuse cached renderitems from last time around
399 if( tryReuseRenderList )
401 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
406 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix );
410 * Add stencil renderers from the layer onto the next free render list
411 * @param updateBufferIndex to use
412 * @param layer to get the renderers from
413 * @param viewmatrix for the camera from rendertask
414 * @param instruction to fill in
415 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
417 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
419 const Matrix& viewMatrix,
420 RenderInstruction& instruction,
421 bool tryReuseRenderList )
423 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.size() );
424 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
425 SetStencilRenderFlags( stencilRenderList );
427 // try to reuse cached renderitems from last time around
428 if( tryReuseRenderList )
430 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
435 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix );
439 * Prepare a single render instruction
440 * @param updateBufferIndex to use
441 * @param sortedLayers to prepare the instruction from
442 * @param renderTask to get the view matrix
443 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
444 * @param renderTracker An optional render tracker object
445 * @param instructions container
447 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
448 SortedLayerPointers& sortedLayers,
449 RenderTask& renderTask,
450 RendererSortingHelper& sortingHelper,
451 RenderTracker* renderTracker,
452 RenderInstructionContainer& instructions )
454 // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
455 // then populate with instructions.
456 RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
457 renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
458 bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
460 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
462 const SortedLayersIter endIter = sortedLayers.end();
463 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
465 Layer& layer = **iter;
467 const bool stencilRenderablesExist( !layer.stencilRenderables.empty() );
468 const bool opaqueRenderablesExist( !layer.opaqueRenderables.empty() );
469 const bool transparentRenderablesExist( !layer.transparentRenderables.empty() );
470 const bool overlayRenderablesExist( !layer.overlayRenderables.empty() );
471 const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
473 // Ignore stencils if there's nothing to test
474 if( stencilRenderablesExist &&
475 ( opaqueRenderablesExist || transparentRenderablesExist || overlayRenderablesExist ) )
477 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, instruction, tryReuseRenderList );
480 if ( opaqueRenderablesExist )
482 AddOpaqueRenderers( updateBufferIndex,
485 transparentRenderablesExist,
486 stencilRenderablesExist,
488 tryReuseRenderList );
491 if ( transparentRenderablesExist )
493 AddTransparentRenderers( updateBufferIndex,
496 opaqueRenderablesExist,
497 stencilRenderablesExist,
500 tryReuseRenderList );
503 if ( overlayRenderablesExist )
505 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist,
506 instruction, tryReuseRenderList );
510 instruction.mRenderTracker = renderTracker;
511 instruction.mCullMode = renderTask.GetCullMode();
513 // inform the render instruction that all renderers have been added and this frame is complete
514 instruction.UpdateCompleted();