From: David Steele Date: Fri, 24 Apr 2015 17:39:51 +0000 (+0100) Subject: Changed depth sorting algorithm. X-Git-Tag: dali_1.0.47~8^2^2~23 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e1fc6046dfb1c1ad54f3fda035741f85264ebaf5;p=platform%2Fcore%2Fuifw%2Fdali-core.git Changed depth sorting algorithm. Opaque items are sorted first by depth index, then by Shader, Geometry and Material. Transparent items are sorted first by depth index, then by distance from camera, then by Shader, Geometry and Material. Changed the render algorithm to interleave the opaque and transparent lists for items at the same depth index. Change-Id: I2c21c986d790a4ac0f2a519e1bb58242537f4f8a Signed-off-by: David Steele --- diff --git a/automated-tests/src/dali/utc-Dali-Layer.cpp b/automated-tests/src/dali/utc-Dali-Layer.cpp index 5c6d1b8..a887f1c 100644 --- a/automated-tests/src/dali/utc-Dali-Layer.cpp +++ b/automated-tests/src/dali/utc-Dali-Layer.cpp @@ -250,7 +250,7 @@ int UtcDaliLayerGetClippingBox(void) static int gTestSortFunctionCalled; -static float TestSortFunction(const Vector3& /*position*/, float /*sortModifier*/) +static float TestSortFunction(const Vector3& /*position*/) { ++gTestSortFunctionCalled; return 0.0f; diff --git a/dali/internal/event/actors/layer-impl.h b/dali/internal/event/actors/layer-impl.h index 76a7ba4..978416d 100644 --- a/dali/internal/event/actors/layer-impl.h +++ b/dali/internal/event/actors/layer-impl.h @@ -44,12 +44,12 @@ class Layer : public Actor public: /** - * @copydoc Dali::Layer::ZValue(const Vector3&, float) + * @copydoc Dali::Layer::ZValue(const Vector3&) */ - static float ZValue(const Vector3& position, float sortModifier) + static float ZValue(const Vector3& position) { // inlined so we avoid a function call when sorting renderers - return position.z + sortModifier; + return position.z; } /** diff --git a/dali/internal/render/common/render-algorithms.cpp b/dali/internal/render/common/render-algorithms.cpp index 30fd6b4..95785de 100644 --- a/dali/internal/render/common/render-algorithms.cpp +++ b/dali/internal/render/common/render-algorithms.cpp @@ -40,28 +40,12 @@ namespace Render { /** - * Process a render-list. - * @param[in] renderList The render-list to process. - * @param[in] context The GL context. - * @param[in] defaultShader The default shader to use. - * @param[in] buffer The current render buffer index (previous update buffer) - * @param[in] frameTime The elapsed time between the last two updates. - * @param[in] viewMatrix The view matrix from the appropriate camera. - * @param[in] projectionMatrix The projection matrix from the appropriate camera. - * @param[in] cullMode True if the renderers should be subjected to clipspace culling + * Sets up the scissor test if required. + * @param[in] renderList The render list from which to get the clipping flag + * @param[in] context The context */ -inline void ProcessRenderList( const RenderList& renderList, - Context& context, - SceneGraph::TextureCache& textureCache, - SceneGraph::Shader& defaultShader, - BufferIndex bufferIndex, - float frameTime, - const Matrix& viewMatrix, - const Matrix& projectionMatrix, - bool cullMode ) +inline void SetScissorTest( const RenderList& renderList, Context& context ) { - DALI_PRINT_RENDER_LIST( renderList ); - // Scissor testing if( renderList.IsClipping() ) { @@ -74,7 +58,16 @@ inline void ProcessRenderList( const RenderList& renderList, { context.SetScissorTest( false ); } +} +/** + * Sets the render flags for depth testing and stencil buffer + * + * @param[in] renderList The render list from which to get the render flags + * @param[in] context The context + */ +inline void SetRenderFlags( const RenderList& renderList, Context& context ) +{ const unsigned int renderFlags = renderList.GetFlags(); bool enableDepthBuffer = ( ( renderFlags & RenderList::DEPTH_BUFFER_ENABLED ) != 0u ); @@ -109,6 +102,35 @@ inline void ProcessRenderList( const RenderList& renderList, // only clear if the depth and/or stencil buffer have been written to after a previous clear context.Clear( clearMask, Context::CHECK_CACHED_VALUES ); } +} + + +/** + * Process a render-list. + * @param[in] renderList The render-list to process. + * @param[in] context The GL context. + * @param[in] defaultShader The default shader to use. + * @param[in] buffer The current render buffer index (previous update buffer) + * @param[in] frameTime The elapsed time between the last two updates. + * @param[in] viewMatrix The view matrix from the appropriate camera. + * @param[in] projectionMatrix The projection matrix from the appropriate camera. + * @param[in] cullMode True if the renderers should be subjected to clipspace culling + */ +inline void ProcessRenderList( + const RenderList& renderList, + Context& context, + SceneGraph::TextureCache& textureCache, + SceneGraph::Shader& defaultShader, + BufferIndex bufferIndex, + float frameTime, + const Matrix& viewMatrix, + const Matrix& projectionMatrix, + bool cullMode ) +{ + DALI_PRINT_RENDER_LIST( renderList ); + + SetScissorTest( renderList, context ); + SetRenderFlags( renderList, context ); size_t count = renderList.Count(); for ( size_t index = 0; index < count; ++index ) @@ -124,6 +146,139 @@ inline void ProcessRenderList( const RenderList& renderList, } } +/** + * Render items from the currentIndex until the depth index changes. + * Leaves currentIndex pointing at the + * + * @param[in] renderList The render-list to process. + * @param[in] context The GL context. + * @param[in] defaultShader The default shader to use. + * @param[in] buffer The current render buffer index (previous update buffer) + * @param[in] frameTime The elapsed time between the last two updates. + * @param[in] viewMatrix The view matrix from the appropriate camera. + * @param[in] projectionMatrix The projection matrix from the appropriate camera. + * @param[in] cullMode True if the renderers should be subjected to clipspace culling + * @param[in] depthIndex The current depth index + * @param[inout] currentIndex On entry, the index in the render list of the first item at the given depth index. On exit, the index of the first item at the next depth index. + */ +inline void RenderItemsAtDepthIndex( + const RenderList& renderList, + Context& context, + SceneGraph::TextureCache& textureCache, + SceneGraph::Shader& defaultShader, + BufferIndex bufferIndex, + float frameTime, + const Matrix& viewMatrix, + const Matrix& projectionMatrix, + bool cullMode, + int depthIndex, + size_t& currentIndex ) // Out parameter +{ + const size_t count = renderList.Count(); + + // Don't initialise currentIndex. Ever. + for( ; currentIndex < count ; currentIndex++ ) + { + const RenderItem& renderItem = renderList.GetItem( currentIndex ); + DALI_PRINT_RENDER_ITEM( renderItem ); + + if( renderItem.GetDepthIndex() == depthIndex ) + { + SceneGraph::Renderer* renderer = const_cast< SceneGraph::Renderer* >( renderItem.GetRenderer() ); + const Matrix& modelViewMatrix = renderItem.GetModelViewMatrix(); + renderer->Render( context, textureCache, bufferIndex, defaultShader, modelViewMatrix, viewMatrix, projectionMatrix, frameTime, cullMode ); + + } + else + { + break; // Stop iterating when we reach a new depth index + } + } +} + + +/** + * Process two interleaved render-lists. + * + * For each depth index, it will set the flags for the first list, + * render items in the first list, set flags for the second list and + * render items from the second list. + * + * @param[in] renderList1 The first render-list to process. + * @param[in] renderList2 The second render-list to process. + * @param[in] context The GL context. + * @param[in] defaultShader The default shader to use. + * @param[in] buffer The current render buffer index (previous update buffer) + * @param[in] frameTime The elapsed time between the last two updates. + * @param[in] viewMatrix The view matrix from the appropriate camera. + * @param[in] projectionMatrix The projection matrix from the appropriate camera. + * @param[in] cullMode True if the renderers should be subjected to clipspace culling + */ + +inline void ProcessInterleavedRenderLists( + const RenderList& renderList1, + const RenderList& renderList2, + Context& context, + SceneGraph::TextureCache& textureCache, + SceneGraph::Shader& defaultShader, + BufferIndex bufferIndex, + float frameTime, + const Matrix& viewMatrix, + const Matrix& projectionMatrix, + bool cullMode ) +{ + + SetScissorTest( renderList1, context ); // Scissor settings are identical for both lists + size_t count1 = renderList1.Count(); + size_t count2 = renderList2.Count(); + size_t index1 = 0; + size_t index2 = 0; + + int depthIndex=renderList1.GetItem( 0 ).GetDepthIndex(); + + while( index1 < count1 || index2 < count2 ) + { + if( index1 < count1 && index2 < count2 ) + { + // Take the lowest depth index in both lists + depthIndex = std::min( renderList1.GetItem( index1 ).GetDepthIndex(), + renderList2.GetItem( index2 ).GetDepthIndex() ); + } + else if( index1 < count1 ) + { + // Items left only in list 1 + depthIndex = renderList1.GetItem( index1 ).GetDepthIndex(); + } + else // index2 < count2 + { + // Items left only in list 2 + depthIndex = renderList2.GetItem( index2 ).GetDepthIndex(); + } + + // Between each successive depth index, reset the flags. + SetRenderFlags( renderList1, context ); + + // Find and render items in the first list that correspond to the current depth index + if( index1 < count1 ) + { + RenderItemsAtDepthIndex( renderList1, context, textureCache, defaultShader, + bufferIndex, frameTime, viewMatrix, projectionMatrix, + cullMode, depthIndex, + index1 ); // Out parameter + } + + SetRenderFlags( renderList2, context ); + if( index2 < count2 ) + { + RenderItemsAtDepthIndex( renderList2, context, textureCache, defaultShader, + bufferIndex, frameTime, viewMatrix, projectionMatrix, + cullMode, depthIndex, + index2 ); // Out parameter + } + } +} + + void ProcessRenderInstruction( const RenderInstruction& instruction, Context& context, SceneGraph::TextureCache& textureCache, @@ -143,6 +298,9 @@ void ProcessRenderInstruction( const RenderInstruction& instruction, NULL != projectionMatrix ) { const RenderListContainer::SizeType count = instruction.RenderListCount(); + + // Iterate through each render list in order. If a pair of render lists + // are marked as interleaved, then process them together. for( RenderListContainer::SizeType index = 0; index < count; ++index ) { const RenderList* renderList = instruction.GetRenderList( index ); @@ -150,7 +308,26 @@ void ProcessRenderInstruction( const RenderInstruction& instruction, if( renderList && !renderList->IsEmpty() ) { - ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, frameTime, *viewMatrix, *projectionMatrix, instruction.mCullMode ); + if( renderList->GetInterleave() && + index < count-1 && + instruction.GetRenderList(index+1)->GetInterleave() ) + { + ProcessInterleavedRenderLists( *renderList, + *(instruction.GetRenderList(index+1)), + context, + textureCache, + defaultShader, + bufferIndex, + frameTime, + *viewMatrix, + *projectionMatrix, + instruction.mCullMode ); + index++; // Skip over next render list + } + else + { + ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, frameTime, *viewMatrix, *projectionMatrix, instruction.mCullMode ); + } } } } diff --git a/dali/internal/render/common/render-item.cpp b/dali/internal/render/common/render-item.cpp index ae7b584..63e868f 100644 --- a/dali/internal/render/common/render-item.cpp +++ b/dali/internal/render/common/render-item.cpp @@ -31,8 +31,9 @@ namespace SceneGraph { RenderItem::RenderItem() -: mRenderer( NULL ), - mModelViewMatrix( false ) +: mModelViewMatrix( false ), + mRenderer( NULL ), + mDepthIndex(0) { } @@ -65,6 +66,11 @@ const Matrix& RenderItem::GetModelViewMatrix() const return mModelViewMatrix; } +void RenderItem::SetDepthIndex( int depthIndex ) +{ + mDepthIndex = depthIndex; +} + } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/render/common/render-item.h b/dali/internal/render/common/render-item.h index bb3321e..35c1107 100644 --- a/dali/internal/render/common/render-item.h +++ b/dali/internal/render/common/render-item.h @@ -83,15 +83,28 @@ public: */ const Matrix& GetModelViewMatrix() const; + /** + * Retrieve the depth index + */ + int GetDepthIndex() const + { + return mDepthIndex; + } + + /** + * Set the depth index + */ + void SetDepthIndex( int depthIndex ); + private: // RenderItems should not be copied as they are heavy RenderItem( const RenderItem& item ); - RenderItem& operator=( const RenderItem& item ); + RenderItem& operator = ( const RenderItem& item ); + Matrix mModelViewMatrix; Renderer* mRenderer; - Matrix mModelViewMatrix; - + int mDepthIndex; }; } // namespace SceneGraph diff --git a/dali/internal/render/common/render-list.h b/dali/internal/render/common/render-list.h index f435628..192f5f3 100644 --- a/dali/internal/render/common/render-list.h +++ b/dali/internal/render/common/render-list.h @@ -77,7 +77,8 @@ public: : mNextFree( 0 ), mRenderFlags( 0u ), mClippingBox( NULL ), - mSourceLayer( NULL ) + mSourceLayer( NULL ), + mInterleave(false) { } @@ -283,6 +284,25 @@ public: mSourceLayer = layer; } + /** + * Determine if this render list should be interleaved with it's adjacent + * neighbour. + * @return true if the render list should be interleaved + */ + bool GetInterleave() const + { + return mInterleave; + } + + /** + * Set the interleave flag for this render list + * @param[in] interleave The interleave flag. + */ + void SetInterleave(bool interleave) + { + mInterleave = interleave; + } + private: /* @@ -294,11 +314,11 @@ private: RenderItemContainer mItems; ///< Each item is a renderer and matrix pair RenderItemContainer::SizeType mNextFree; ///< index for the next free item to use - unsigned int mRenderFlags; ///< The render flags - - ClippingBox* mClippingBox; ///< The clipping box, in window coordinates, when clipping is enabled - Layer* mSourceLayer; ///< The originating layer where the renderers are from + unsigned int mRenderFlags; ///< The render flags + ClippingBox* mClippingBox; ///< The clipping box, in window coordinates, when clipping is enabled + Layer* mSourceLayer; ///< The originating layer where the renderers are from + bool mInterleave; ///< True if render list should be interleaved }; } // namespace SceneGraph diff --git a/dali/internal/update/manager/prepare-render-instructions.cpp b/dali/internal/update/manager/prepare-render-instructions.cpp index bc637ed..27c074c 100644 --- a/dali/internal/update/manager/prepare-render-instructions.cpp +++ b/dali/internal/update/manager/prepare-render-instructions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include // INTERNAL INCLUDES +#include #include // for the default sorting function #include #include @@ -31,6 +32,13 @@ #include #include +namespace +{ +#if defined(DEBUG_ENABLED) +Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS"); +#endif +} + namespace Dali { @@ -51,20 +59,26 @@ inline void SetOpaqueRenderFlags( RenderList& renderList, bool transparentRender { //@todo MESH_REWORK Move RequiresDepthTest from render thread object to update thread object + renderList.SetInterleave(transparentRenderersExist); + // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image) // and this renderer does not need depth test against itself (e.g. mesh) // and if this layer has got exactly one opaque renderer // and this renderer is not interested in depth testing // (i.e. is an image and not a mesh) - if ( ( ( renderList.Count() == 1 ) && - ( !transparentRenderersExist ) && - ( !renderList.GetRenderer( 0 )->RequiresDepthTest() ) ) || - depthTestDisabled ) + if ( ( renderList.Count() == 1 ) && + ( !transparentRenderersExist ) && + ( !renderList.GetRenderer( 0 )->RequiresDepthTest() ) ) { // no need to enable depth test or clear depth buffer // if there's something transparent already rendered by previous layers, // this opaque renderer will correctly draw on top of them since no depth test renderList.ClearFlags(); + renderList.SetInterleave(false); + } + else if( depthTestDisabled ) + { + renderList.ClearFlags(); } else { @@ -94,12 +108,12 @@ inline void SetTransparentRenderFlags( RenderList& renderList, bool opaqueRender // We don't need to write to the depth buffer, as transparent objects // don't obscure each other. + renderList.SetInterleave(opaqueRenderersExist); if ( opaqueRenderersExist && !depthTestDisabled ) { // If there are a mix of opaque and transparent objects, the transparent // objects should be rendered with depth test on to avoid background objects // appearing in front of opaque foreground objects. - renderList.SetFlags( RenderList::DEPTH_BUFFER_ENABLED ); } @@ -150,6 +164,7 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex, // Get the next free RenderItem RenderItem& item = renderList.GetNextFreeItem(); item.SetRenderer( const_cast< Renderer* >( &renderer ) ); + item.SetDepthIndex( renderable.GetDepthIndex(updateBufferIndex) ); // calculate MV matrix onto the item Matrix& modelViewMatrix = item.GetModelViewMatrix(); @@ -170,12 +185,18 @@ inline void AddRenderersToRenderList( BufferIndex updateBufferIndex, RenderableAttachmentContainer& attachments, const Matrix& viewMatrix ) { + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n"); + // Add renderer for each attachment + int index=0; const RenderableAttachmentIter endIter = attachments.end(); for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter ) { RenderableAttachment& attachment = **iter; AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix ); + + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " List[%d].renderer = %p\n", index, &(attachment.GetRenderer())); + index++; } } @@ -219,6 +240,111 @@ inline bool TryReuseCachedRenderers( Layer& layer, return retValue; } + +/** + * Function which sorts render items by depth index then by instance + * ptrs of shader/geometry/material. + * @param lhs item + * @param rhs item + * @return true if left item is greater than right + */ +bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs ) +{ + // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that + // encapsulates the same data (e.g. the middle-order bits of the ptrs) + if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() ) + { + if( lhs.shader == rhs.shader ) + { + if( lhs.material == rhs.material ) + { + return lhs.geometry < lhs.geometry; + } + return lhs.material < rhs.material; + } + return lhs.shader < rhs.shader;; + } + return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex(); +} +/** + * Function which sorts the render items by depth index then by Z function, + * then by instance ptrs of shader/geometry/material. + * @param lhs item + * @param rhs item + * @return true if left item is greater than right + */ +bool CompareItemsWithZValue( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs ) +{ + // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that + // encapsulates the same data (e.g. the middle-order bits of the ptrs) + + if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() ) + { + if( Equals(lhs.zValue, rhs.zValue) ) + { + if( lhs.shader == rhs.shader ) + { + if( lhs.material == rhs.material ) + { + return lhs.geometry < lhs.geometry; + } + return lhs.material < rhs.material; + } + return lhs.shader < rhs.shader;; + } + return lhs.zValue > rhs.zValue; + } + return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex(); +} + +inline void SortOpaqueRenderItems( + BufferIndex bufferIndex, + RenderList& opaqueRenderList, + Layer& layer, + RenderItemSortingHelper& sortingHelper ) +{ + const size_t renderableCount = opaqueRenderList.Count(); + // reserve space if needed + const unsigned int oldcapacity = sortingHelper.size(); + if( oldcapacity < renderableCount ) + { + sortingHelper.reserve( renderableCount ); + // add real objects (reserve does not construct objects) + sortingHelper.insert( sortingHelper.begin() + oldcapacity, + (renderableCount - oldcapacity), + RendererWithSortAttributes() ); + } + else + { + // clear extra elements from helper, does not decrease capability + sortingHelper.resize( renderableCount ); + } + + for( size_t index = 0; index < renderableCount; ++index ) + { + RenderItem& item = opaqueRenderList.GetItem( index ); + + //@todo MESH_REWORK After merge of RenderableAttachment and RendererAttachment, should instead store the renderable ptr and get the fields directly + layer.opaqueRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] ); + + sortingHelper[ index ].zValue = 0; + sortingHelper[ index ].renderItem = &item; + } + + // Sort the renderers by depth index, then by instance + std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems ); + + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Opaque List:\n"); + + // Repopulate the render items in the render list based on the sorting helper + RenderItemContainer::Iterator renderListIter = opaqueRenderList.GetContainer().Begin(); + for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter ) + { + *renderListIter = sortingHelper[ index ].renderItem; + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", sortingHelper[ index ].renderItem->GetRenderer() ); + } +} + /** * Add opaque renderers from the layer onto the next free render list * @param updateBufferIndex to use @@ -235,8 +361,10 @@ inline void AddOpaqueRenderers( BufferIndex updateBufferIndex, bool transparentRenderablesExist, bool stencilRenderablesExist, RenderInstruction& instruction, + RendererSortingHelper& sortingHelper, bool tryReuseRenderList ) { + const size_t renderableCount = layer.opaqueRenderables.size(); RenderList& opaqueRenderList = instruction.GetNextFreeRenderList( layer.opaqueRenderables.size() ); opaqueRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() ); @@ -255,26 +383,22 @@ inline void AddOpaqueRenderers( BufferIndex updateBufferIndex, // opaque flags can only be set after renderers are added SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() ); -} -/** - * Function which sorts based on the calculated depth values ordering them back to front - * @param lhs item - * @param rhs item - * @return true if left item is greater than right - */ -bool SortByDepthSortValue( const RendererWithSortValue& lhs, const RendererWithSortValue& rhs ) -{ - return lhs.first > rhs.first; + // sorting is only needed if more than 1 item + if( renderableCount > 1 ) + { + SortOpaqueRenderItems( updateBufferIndex, opaqueRenderList, layer, sortingHelper.opaque ); + } } + /** * Sort transparent render items * @param transparentRenderList to sort * @param layer where the renderers are from * @param sortingHelper to use for sorting the renderitems (to avoid reallocating) */ -inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer& layer, RendererSortingHelper& sortingHelper ) +inline void SortTransparentRenderItems( BufferIndex bufferIndex, RenderList& transparentRenderList, Layer& layer, RenderItemSortingHelper& sortingHelper ) { const size_t renderableCount = transparentRenderList.Count(); // reserve space if needed @@ -285,13 +409,14 @@ inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer // add real objects (reserve does not construct objects) sortingHelper.insert( sortingHelper.begin() + oldcapacity, (renderableCount - oldcapacity), - RendererWithSortValue( 0.0f, NULL ) ); + RendererWithSortAttributes() ); } else { // clear extra elements from helper, does not decrease capability sortingHelper.resize( renderableCount ); } + // calculate the sorting value, once per item by calling the layers sort function // Using an if and two for-loops rather than if inside for as its better for branch prediction if( layer.UsesDefaultSortFunction() ) @@ -299,12 +424,15 @@ inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer for( size_t index = 0; index < renderableCount; ++index ) { RenderItem& item = transparentRenderList.GetItem( index ); + + //@todo MESH_REWORK After merge of RenderableAttachment and RendererAttachment, should instead store the renderable ptr and get the fields directly + layer.transparentRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] ); + // the default sorting function should get inlined here - sortingHelper[ index ].first = Internal::Layer::ZValue( - item.GetModelViewMatrix().GetTranslation3(), - layer.transparentRenderables[ index ]->GetSortModifier() ); + sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() ); + // keep the renderitem pointer in the helper so we can quickly reorder items after sort - sortingHelper[ index ].second = &item; + sortingHelper[ index ].renderItem = &item; } } else @@ -313,22 +441,25 @@ inline void SortTransparentRenderItems( RenderList& transparentRenderList, Layer for( size_t index = 0; index < renderableCount; ++index ) { RenderItem& item = transparentRenderList.GetItem( index ); - sortingHelper[ index ].first = (*sortFunction)( - item.GetModelViewMatrix().GetTranslation3(), - layer.transparentRenderables[ index ]->GetSortModifier() ); + + layer.transparentRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] ); + sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() ); + // keep the renderitem pointer in the helper so we can quickly reorder items after sort - sortingHelper[ index ].second = &item; + sortingHelper[ index ].renderItem = &item; } } // sort the renderers back to front, Z Axis point from near plane to far plane - std::sort( sortingHelper.begin(), sortingHelper.end(), SortByDepthSortValue ); + std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItemsWithZValue ); // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n"); RenderItemContainer::Iterator renderListIter = transparentRenderList.GetContainer().Begin(); for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter ) { - *renderListIter = sortingHelper[ index ].second; + *renderListIter = sortingHelper[ index ].renderItem; + DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, sortingHelper[ index ].renderItem->GetRenderer() ); } } @@ -355,6 +486,7 @@ inline void AddTransparentRenderers( BufferIndex updateBufferIndex, const size_t renderableCount = layer.transparentRenderables.size(); RenderList& transparentRenderList = instruction.GetNextFreeRenderList( renderableCount ); transparentRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() ); + // transparent flags are independent of the amount of transparent renderers SetTransparentRenderFlags( transparentRenderList, opaqueRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() ); @@ -373,7 +505,7 @@ inline void AddTransparentRenderers( BufferIndex updateBufferIndex, // sorting is only needed if more than 1 item if( renderableCount > 1 ) { - SortTransparentRenderItems( transparentRenderList, layer, sortingHelper ); + SortTransparentRenderItems( updateBufferIndex, transparentRenderList, layer, sortingHelper.transparent ); } } @@ -487,6 +619,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex, transparentRenderablesExist, stencilRenderablesExist, instruction, + sortingHelper, tryReuseRenderList ); } @@ -502,6 +635,9 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex, tryReuseRenderList ); } + // @todo MESH_REWORK Mark opaque and transparent render lists as interleaveable. + // ( Saves having to have a pair of lists for each depth index ) + if ( overlayRenderablesExist ) { AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist, diff --git a/dali/internal/update/manager/prepare-render-instructions.h b/dali/internal/update/manager/prepare-render-instructions.h index d1f1c4a..b773752 100644 --- a/dali/internal/update/manager/prepare-render-instructions.h +++ b/dali/internal/update/manager/prepare-render-instructions.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_PREPARE_RENDER_INSTRUCTIONS_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,15 +32,54 @@ namespace SceneGraph { class RenderTracker; class RenderItem; -typedef std::pair< float, RenderItem* > RendererWithSortValue; -typedef std::vector< RendererWithSortValue > RendererSortingHelper; +class Shader; +class Material; +class Geometry; + +/** + * Structure to store information for sorting the renderers. + * (Note, depthIndex is stored within the renderItem). + */ +struct RendererWithSortAttributes +{ + RendererWithSortAttributes() + : renderItem( NULL ), + shader(NULL), + material(NULL), + geometry(NULL), + zValue(0.0f) + { + } + + RenderItem* renderItem; ///< The render item that is being sorted (includes depth index) + Shader* shader; ///< The shader instance + Material* material; ///< The material instance + Geometry* geometry; ///< The geometry instance + float zValue; // The zValue of the given renderer (either distance from camera, or a custom calculated value) +}; + +typedef std::vector< RendererWithSortAttributes > RenderItemSortingHelper; + +struct RendererSortingHelper +{ + RenderItemSortingHelper transparent; + RenderItemSortingHelper opaque; +}; class RenderTask; class RenderInstructionContainer; /** - * Sorts and prepares the list of opaque/transparent renderable attachments for each layer. - * Whilst iterating through each layer, update the attachments ModelView matrices + * Sorts and prepares the list of opaque/transparent renderable + * attachments for each layer. Whilst iterating through each layer, + * update the attachments ModelView matrices + * + * The opaque and transparent render lists are sorted first by depth + * index, then by Z (for transparent only), then by shader, material + * and geometry. The render algorithm should then work through both + * lists simultaneously, working through opaque then transparent + * items at each depth index, resetting the flags appropriately. + * * @param[in] updateBufferIndex The current update buffer index. * @param[in] sortedLayers The layers containing lists of opaque/transparent renderables. * @param[in] renderTask The rendering task information. diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 60f2d11..803573e 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -576,7 +576,7 @@ inline void AttachToNodeMessage( UpdateManager& manager, const Node& constParent // Scene graph thread can modify this object. Node& parent = const_cast< Node& >( constParent ); - // @todo MESH_REWORK Don't pass by owner pointer after merge with SceneGraph::RenderableAttachment + // @todo MESH_REWORK Don't pass by owner pointer after merge with SceneGraph::RenderableAttachment ? (not needed if we split RendererAttachment to 2 objects) typedef MessageValue2< UpdateManager, Node*, NodeAttachmentOwner > LocalType; // Reserve some memory inside the message queue diff --git a/dali/internal/update/node-attachments/scene-graph-renderable-attachment.cpp b/dali/internal/update/node-attachments/scene-graph-renderable-attachment.cpp index 4568673..28a7f62 100644 --- a/dali/internal/update/node-attachments/scene-graph-renderable-attachment.cpp +++ b/dali/internal/update/node-attachments/scene-graph-renderable-attachment.cpp @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include #include +#include #include #include #include @@ -250,6 +251,12 @@ void RenderableAttachment::SetSortModifier(float modifier) mSortModifier = modifier; } +void RenderableAttachment::SetSortAttributes( BufferIndex bufferIndex, RendererWithSortAttributes& sortAttributes ) +{ + sortAttributes.shader = mShader; + sortAttributes.material = NULL; + sortAttributes.geometry = NULL; +} } // namespace SceneGraph diff --git a/dali/internal/update/node-attachments/scene-graph-renderable-attachment.h b/dali/internal/update/node-attachments/scene-graph-renderable-attachment.h index a525d7b..3f87a6b 100644 --- a/dali/internal/update/node-attachments/scene-graph-renderable-attachment.h +++ b/dali/internal/update/node-attachments/scene-graph-renderable-attachment.h @@ -41,6 +41,8 @@ namespace SceneGraph { class Renderer; class Shader; +class SortAttributes; +struct RendererWithSortAttributes; /** * RenderableAttachments are responsible for preparing textures, meshes, matrices etc. during the Update. @@ -236,7 +238,6 @@ public: // API for derived classes */ virtual void DoGetScaleForSize( const Vector3& nodeSize, Vector3& scaling ); - /** * Set the sort-modifier for the attachment. * @param[in] modifier The depth-sort modifier. @@ -244,15 +245,24 @@ public: // API for derived classes void SetSortModifier(float modifier); /** - * Retrieve the sort-modifier for the attachment. - * @return The sort-modifier. + * Get the depth index for the attachment + * @param[in] bufferIndex The current update buffer index. */ - float GetSortModifier() const + virtual int GetDepthIndex(BufferIndex bufferIndex) { - // inlined as its called a lot when sorting transparent renderers - return mSortModifier; + return static_cast( mSortModifier ); } + /** + * Write the attachment's sort attributes to the passed in reference + * @todo MESH_REWORK Consider removing this after merge with scene-graph-renderer-attachment, + * and allowing PrepareRenderInstruction to read directly from this object + * + * @param[in] bufferIndex The current update buffer index. + * @param[out] sortAttributes + */ + virtual void SetSortAttributes( BufferIndex bufferIndex, RendererWithSortAttributes& sortAttributes ); + private: // Undefined diff --git a/dali/internal/update/node-attachments/scene-graph-renderer-attachment.cpp b/dali/internal/update/node-attachments/scene-graph-renderer-attachment.cpp index 148e09b..0ded538 100644 --- a/dali/internal/update/node-attachments/scene-graph-renderer-attachment.cpp +++ b/dali/internal/update/node-attachments/scene-graph-renderer-attachment.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -151,18 +152,22 @@ Geometry& RendererAttachment::GetGeometry() return *mGeometry; } +void RendererAttachment::SetSortAttributes( BufferIndex bufferIndex, RendererWithSortAttributes& sortAttributes ) +{ + sortAttributes.shader = mMaterial->GetShader(); + sortAttributes.material = mMaterial; + sortAttributes.geometry = mGeometry; +} + void RendererAttachment::SetDepthIndex( BufferIndex updateBufferIndex, int depthIndex ) { mDepthIndex.Bake(updateBufferIndex, depthIndex); if( mParent ) { - // only do this if we are on-stage + // only do this if we are on-stage. Ensures the render lists are re-sorted mParent->SetDirtyFlag( SortModifierFlag ); } - - // @todo MESH_REWORK Change SortTransparentRenderItems to use GetDepthIndex instead - mSortModifier = depthIndex; } void RendererAttachment::ResetToBaseValues( BufferIndex updateBufferIndex ) diff --git a/dali/internal/update/node-attachments/scene-graph-renderer-attachment.h b/dali/internal/update/node-attachments/scene-graph-renderer-attachment.h index 670a277..bd71042 100644 --- a/dali/internal/update/node-attachments/scene-graph-renderer-attachment.h +++ b/dali/internal/update/node-attachments/scene-graph-renderer-attachment.h @@ -36,6 +36,7 @@ namespace SceneGraph class Material; class Geometry; class NewRenderer; +struct RendererWithSortAttributes; /** * The renderer attachment is the SceneGraph equivalent of Dali::Renderer. It is used to create an instance of a geometry and material for rendering, and is attached to an actor. @@ -131,22 +132,26 @@ public: */ void SetDepthIndex( BufferIndex bufferIndex, int depthIndex ); +protected: // From NodeAttachment + /** + * @copydoc NodeAttachment::ResetToBaseValues + */ + virtual void ResetToBaseValues( BufferIndex updateBufferIndex ); + /** - * Get the depth index. - * Inlined, as called from sort algorithm - * @return The depth index of the renderer attachment in the current frame + * @param[in] bufferIndex The buffer index */ - int GetDepthIndex( BufferIndex bufferIndex ) const + virtual int GetDepthIndex( BufferIndex bufferIndex ) { return mDepthIndex[bufferIndex]; } - -protected: // From NodeAttachment /** - * @copydoc NodeAttachment::ResetToBaseValues + * Write the attachment's sort attributes to the passed in reference. + * @param[in] bufferIndex The buffer index + * @param[out] sortAttributes */ - virtual void ResetToBaseValues( BufferIndex updateBufferIndex ); + virtual void SetSortAttributes( BufferIndex bufferIndex, RendererWithSortAttributes& sortAttributes ); protected: // From RenderableAttachment /** diff --git a/dali/public-api/actors/layer.cpp b/dali/public-api/actors/layer.cpp index c8c1413..3c0de03 100644 --- a/dali/public-api/actors/layer.cpp +++ b/dali/public-api/actors/layer.cpp @@ -138,9 +138,9 @@ bool Layer::IsDepthTestDisabled() const return GetImplementation(*this).IsDepthTestDisabled(); } -float Layer::ZValue(const Vector3& position, float sortModifier) +float Layer::ZValue(const Vector3& position) { - return Internal::Layer::ZValue( position, sortModifier ); + return Internal::Layer::ZValue( position ); } void Layer::SetSortFunction(SortFunctionType function) @@ -174,4 +174,3 @@ Layer::Layer(Internal::Layer* internal) } } // namespace Dali - diff --git a/dali/public-api/actors/layer.h b/dali/public-api/actors/layer.h index eb838c4..76cf1d2 100644 --- a/dali/public-api/actors/layer.h +++ b/dali/public-api/actors/layer.h @@ -81,14 +81,9 @@ public: /** * @brief The sort function type. * - * The position value is the actor translation from camera. - * The sortModifier is the user value that can be used to sort coplanar actors/nodes. This value is - * the one set by calling RenderableActor::SetSortModifier(). - * - * A high return value means that the actor will be positioned further away by the sort algorithm. - * @see RenderableActor::SetSortModifier + * @param[in] position this is the actor translation from camera. */ - typedef float (*SortFunctionType)(const Vector3& position, float sortModifier); + typedef float (*SortFunctionType)( const Vector3& position ); /** * @brief Create an empty Layer handle. @@ -294,10 +289,9 @@ public: * We return a negative z value as in our translation, a low z means that it should * be sorted further away and a high z means that it should be closer. * @param[in] position position of actor in view space - * @param[in] sortModifier additional sort modifer * @return depth */ - static float ZValue(const Vector3& position, float sortModifier); + static float ZValue(const Vector3& position ); /** * @brief This allows the user to specify the sort function that the layer should use. @@ -307,7 +301,7 @@ public: * * A function of the following type should be used: * @code - * float YourSortFunction(const Vector3& position, float sortModifier); + * float YourSortFunction(const Vector3& position); * @endcode * * @note If the sort function returns a low number, the actor the data applies to will be