Added sibling order property to Actor 20/100620/8
authorFerran Sole <ferran.sole@samsung.com>
Mon, 28 Nov 2016 15:04:06 +0000 (15:04 +0000)
committerFerran Sole <ferran.sole@samsung.com>
Thu, 1 Dec 2016 15:16:11 +0000 (15:16 +0000)
- Added a sibling order to allow the user to control drawing order in LAYER_UI

Change-Id: Ife3995b46d61ebe7abbc39b6035834b7a581c674

automated-tests/src/dali/utc-Dali-Renderer.cpp
dali/devel-api/actors/actor-devel.h
dali/devel-api/actors/layer-devel.h [new file with mode: 0644]
dali/devel-api/file.list
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/manager/render-task-processor.cpp
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h

index 8d1bc31..0a89471 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+
 #include <dali/public-api/dali-core.h>
 #include <dali/devel-api/images/texture-set-image.h>
 #include <cstdio>
@@ -1645,6 +1647,157 @@ int UtcDaliRendererRenderOrder2DLayerMultipleRenderers(void)
   END_TEST;
 }
 
+int UtcDaliRendererRenderOrder2DLayerDepthIndex(void)
+{
+  TestApplication application;
+  tet_infoline("Test the rendering order in a 2D layer is correct using multiple renderers per actor");
+
+  /*
+   * Creates the following hierarchy:
+   *
+   *                            Layer
+   *                           /    \
+   *                         /        \
+   *                       /            \
+   *                     /                \
+   *                   /                    \
+   *             actor0 (SIBLING_ORDER:1)     actor1 (SIBLING_ORDER:0)
+   *            /   |   \                    /   |   \
+   *          /     |     \                /     |     \
+   *        /       |       \            /       |       \
+   * renderer0 renderer1  actor2     renderer2 renderer3 renderer4
+   *                        |
+   *                        |
+   *                   renderer5
+   *
+   *  actor0 has sibling order 1
+   *  actor1 has sibling order 0
+   *  actor2 has sibling order 0
+   *
+   *  renderer0 has depth index 2
+   *  renderer1 has depth index 0
+   *
+   *  renderer2 has depth index 0
+   *  renderer3 has depth index 1
+   *  renderer4 has depth index 2
+   *
+   *  renderer5 has depth index -1
+   *
+   *  Expected rendering order: renderer2 - renderer3 - renderer4 - renderer1 - renderer0 - renderer5
+   */
+
+  Shader shader = Shader::New("VertexSource", "FragmentSource");
+  Geometry geometry = CreateQuadGeometry();
+
+  Actor actor0 = Actor::New();
+  actor0.SetAnchorPoint(AnchorPoint::CENTER);
+  actor0.SetParentOrigin(AnchorPoint::CENTER);
+  actor0.SetPosition(0.0f,0.0f);
+  actor0.SetSize(1, 1);
+  actor0.SetProperty( Dali::DevelActor::Property::SIBLING_ORDER, 1 );
+  DALI_TEST_EQUALS( actor0.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 1, TEST_LOCATION );
+  Stage::GetCurrent().Add(actor0);
+
+  Actor actor1 = Actor::New();
+  actor1.SetAnchorPoint(AnchorPoint::CENTER);
+  actor1.SetParentOrigin(AnchorPoint::CENTER);
+  actor1.SetPosition(0.0f,0.0f);
+  actor1.SetSize(1, 1);
+  DALI_TEST_EQUALS( actor1.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 0, TEST_LOCATION );
+  Stage::GetCurrent().Add(actor1);
+
+  Actor actor2 = Actor::New();
+  actor2.SetAnchorPoint(AnchorPoint::CENTER);
+  actor2.SetParentOrigin(AnchorPoint::CENTER);
+  actor2.SetPosition(0.0f,0.0f);
+  actor2.SetSize(1, 1);
+  DALI_TEST_EQUALS( actor1.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 0, TEST_LOCATION );
+  actor0.Add(actor2);
+
+  //Renderer0
+  Image image0 = BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet0 = CreateTextureSet( image0 );
+  Renderer renderer0 = Renderer::New( geometry, shader );
+  renderer0.SetTextures( textureSet0 );
+  renderer0.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
+  actor0.AddRenderer(renderer0);
+  application.SendNotification();
+  application.Render(0);
+
+  //Renderer1
+  Image image1= BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet1 = CreateTextureSet( image1 );
+  Renderer renderer1 = Renderer::New( geometry, shader );
+  renderer1.SetTextures( textureSet1 );
+  renderer1.SetProperty( Renderer::Property::DEPTH_INDEX, 0 );
+  actor0.AddRenderer(renderer1);
+  application.SendNotification();
+  application.Render(0);
+
+  //Renderer2
+  Image image2= BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet2 = CreateTextureSet( image2 );
+  Renderer renderer2 = Renderer::New( geometry, shader );
+  renderer2.SetTextures( textureSet2 );
+  renderer2.SetProperty( Renderer::Property::DEPTH_INDEX, 0 );
+  actor1.AddRenderer(renderer2);
+  application.SendNotification();
+  application.Render(0);
+
+  //Renderer3
+  Image image3 = BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet3 = CreateTextureSet( image3 );
+  Renderer renderer3 = Renderer::New( geometry, shader );
+  renderer3.SetTextures( textureSet3 );
+  renderer3.SetProperty( Renderer::Property::DEPTH_INDEX, 1 );
+  actor1.AddRenderer(renderer3);
+  application.SendNotification();
+  application.Render(0);
+
+  //Renderer4
+  Image image4= BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet4 = CreateTextureSet( image4 );
+  Renderer renderer4 = Renderer::New( geometry, shader );
+  renderer4.SetTextures( textureSet4 );
+  renderer4.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
+  actor1.AddRenderer(renderer4);
+  application.SendNotification();
+  application.Render(0);
+
+  //Renderer5
+  Image image5= BufferImage::New( 64, 64, Pixel::RGB888 );
+  TextureSet textureSet5 = CreateTextureSet( image5 );
+  Renderer renderer5 = Renderer::New( geometry, shader );
+  renderer5.SetTextures( textureSet5 );
+  renderer5.SetProperty( Renderer::Property::DEPTH_INDEX, -1 );
+  actor2.AddRenderer(renderer5);
+  application.SendNotification();
+  application.Render(0);
+
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace(true);
+  application.SendNotification();
+  application.Render(0);
+
+  int textureBindIndex[6];
+  for( unsigned int i(0); i<6; ++i )
+  {
+    std::stringstream params;
+    params << GL_TEXTURE_2D<<", "<<i+1;
+    textureBindIndex[i] = gl.GetTextureTrace().FindIndexFromMethodAndParams("BindTexture", params.str() );
+  }
+
+  DALI_TEST_EQUALS( textureBindIndex[2], 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureBindIndex[3], 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureBindIndex[4], 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureBindIndex[1], 3, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureBindIndex[0], 4, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureBindIndex[5], 5, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliRendererRenderOrder2DLayerOverlay(void)
 {
   TestApplication application;
index 86aa2f8..fd7230f 100644 (file)
@@ -93,6 +93,7 @@ enum Type
      * @note The default value is 'false'
      */
   BATCH_PARENT         = CLIPPING_MODE + 1,
+  SIBLING_ORDER          = CLIPPING_MODE + 2,
 };
 
 } // namespace Property
diff --git a/dali/devel-api/actors/layer-devel.h b/dali/devel-api/actors/layer-devel.h
new file mode 100644 (file)
index 0000000..47e7a02
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_LAYER_DEVEL_H
+#define DALI_LAYER_DEVEL_H
+
+/*
+ * Copyright (c) 2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+
+namespace Dali
+{
+
+namespace DevelLayer
+{
+
+  /**
+   * @brief TREE_DEPTH_MULTIPLIER is used by the rendering sorting algorithm to decide which actors to render first.
+   * @SINCE_1_0.0
+   */
+  enum TreeDepthMultiplier
+  {
+    TREE_DEPTH_MULTIPLIER = 1000000,
+  };
+
+  /**
+  * @brief SIBLING_ORDER_MULTIPLIER is used by the rendering sorting algorithm to decide which actors to render first.
+  * @SINCE_1_2.16
+  */
+ enum SiblingOrderMultiplier
+ {
+   SIBLING_ORDER_MULTIPLIER = 1000,
+ };
+
+}
+
+}
+
+#endif  //DALI_LAYER_DEVEL_H
index 1729634..eefdb14 100644 (file)
@@ -21,7 +21,8 @@ devel_api_src_files = \
 # Add devel header files here DALi internal developer files used by Adaptor & Toolkit
 
 devel_api_core_actors_header_files = \
-  $(devel_api_src_dir)/actors/actor-devel.h
+  $(devel_api_src_dir)/actors/actor-devel.h \
+  $(devel_api_src_dir)/actors/layer-devel.h
 
 devel_api_core_animation_header_files = \
   $(devel_api_src_dir)/animation/animation-data.h \
index 1f1a54b..ce9d371 100644 (file)
@@ -24,6 +24,7 @@
 #include <cfloat>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/actors/layer-devel.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/common/constants.h>
 #include <dali/public-api/events/touch-data.h>
@@ -355,6 +356,10 @@ float GetDimensionValue( const Vector3& values, Dimension::Type dimension )
   return GetDimensionValue( values.GetVectorXY(), dimension );
 }
 
+unsigned int GetDepthIndex( uint16_t depth, uint16_t siblingOrder )
+{
+  return depth * Dali::DevelLayer::TREE_DEPTH_MULTIPLIER + siblingOrder * Dali::DevelLayer::SIBLING_ORDER_MULTIPLIER;
+}
 
 } // unnamed namespace
 
@@ -1970,6 +1975,7 @@ Actor::Actor( DerivedType derivedType )
   mName(),
   mId( ++mActorCounter ), // actor ID is initialised to start from 1, and 0 is reserved
   mDepth( 0u ),
+  mSiblingOrder(0u),
   mIsRoot( ROOT_LAYER == derivedType ),
   mIsLayer( LAYER == derivedType || ROOT_LAYER == derivedType ),
   mIsOnStage( false ),
@@ -2071,6 +2077,7 @@ void Actor::RecursiveConnectToStage( ActorContainer& connectionList, unsigned in
 
   mIsOnStage = true;
   mDepth = depth;
+  SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
 
   ConnectToSceneGraph();
 
@@ -2677,6 +2684,24 @@ void Actor::SetDefaultProperty( Property::Index index, const Property::Value& pr
       break;
     }
 
+    case Dali::DevelActor::Property::SIBLING_ORDER:
+       {
+         int value;
+
+         if( property.Get( value ) )
+         {
+           if( static_cast<unsigned int>(value) != mSiblingOrder )
+           {
+             mSiblingOrder = value;
+             if( mIsOnStage )
+             {
+               SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
+             }
+           }
+         }
+         break;
+       }
+
     case Dali::Actor::Property::CLIPPING_MODE:
     {
       ClippingMode::Type convertedValue = mClippingMode;
@@ -3187,6 +3212,12 @@ Property::Value Actor::GetDefaultProperty( Property::Index index ) const
       break;
     }
 
+    case Dali::DevelActor::Property::SIBLING_ORDER:
+    {
+      value = static_cast<int>(mSiblingOrder);
+      break;
+    }
+
     case Dali::Actor::Property::CLIPPING_MODE:
     {
       value = mClippingMode;
index 2b3074f..1d37366 100644 (file)
@@ -1815,7 +1815,9 @@ protected:
   std::string     mName;      ///< Name of the actor
   unsigned int    mId;        ///< A unique ID to identify the actor starting from 1, and 0 is reserved
 
-  unsigned short mDepth                            :12; ///< Cached: The depth in the hierarchy of the actor. Only 4096 levels of depth are supported
+  uint16_t mDepth;            ///< The depth in the hierarchy of the actor. Only 4096 levels of depth are supported
+  uint16_t mSiblingOrder;     ///< The sibling order of the actor
+
   const bool mIsRoot                               : 1; ///< Flag to identify the root actor
   const bool mIsLayer                              : 1; ///< Flag to identify that this is a layer
   bool mIsOnStage                                  : 1; ///< Flag to identify whether the actor is on-stage
index d8e0c0e..75a1f1a 100644 (file)
@@ -225,7 +225,7 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
 
       if( !isLayer3d )
       {
-        item.mDepthIndex += static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER;
+        item.mDepthIndex += renderable.mNode->GetDepthIndex();
       }
 
       // Save ModelView matrix onto the item.
index e620005..ec99e03 100644 (file)
@@ -93,6 +93,7 @@ Layer* FindLayer( Node& node )
  * @param[in] currentLayer The current layer containing lists of opaque/transparent renderables.
  * @param[in] renderTask The current render-task.
  * @param[in] inheritedDrawMode The draw mode of the parent
+ * @param[in] parentDepthIndex The inherited parent node depth index
  * @param[in] currentClippingId The current Clipping Id
  *              Note: ClippingId is passed by reference, so it is permanently modified when traversing back up the tree for uniqueness.
  * @param[in] clippingDepth The current clipping depth
index 73b52ee..150556d 100644 (file)
@@ -74,8 +74,8 @@ Node::Node()
   mExclusiveRenderTask( NULL ),
   mChildren(),
   mClippingDepth( 0u ),
+  mDepthIndex( 0u ),
   mRegenerateUniformMap( 0 ),
-  mDepth( 0u ),
   mDirtyFlags( AllFlags ),
   mDrawMode( DrawMode::NORMAL ),
   mColorMode( DEFAULT_COLOR_MODE ),
@@ -296,7 +296,6 @@ void Node::SetParent( Node& parentNode )
   DALI_ASSERT_ALWAYS(mParent == NULL);
 
   mParent = &parentNode;
-  mDepth = mParent->GetDepth() + 1u;
 
   if( mTransformId != INVALID_TRANSFORM_ID )
   {
@@ -343,7 +342,6 @@ void Node::RecursiveDisconnectFromSceneGraph( BufferIndex updateBufferIndex )
 
   // Remove back-pointer to parent
   mParent = NULL;
-  mDepth = 0u;
 
   // Remove all child pointers
   mChildren.Clear();
index 3cd0117..6e3f98d 100644 (file)
@@ -715,11 +715,6 @@ public:
     return ( this == rhs );
   }
 
-  unsigned short GetDepth() const
-  {
-    return mDepth;
-  }
-
   /**
    * @brief Turns on or off being a batch parent for the node
    * @param[in] enabled If true the node becomes a parent for batch of its children
@@ -727,6 +722,18 @@ public:
   void SetIsBatchParent( bool enabled );
 
   /**
+   * @brief Sets the sibling order of the node
+   * @param[in] order The new order
+   */
+  void SetDepthIndex( unsigned int depthIndex ){ mDepthIndex = depthIndex; }
+
+  /**
+   * @brief Get the depth index of the node
+   * @return Current depth index
+   */
+  unsigned int GetDepthIndex(){ return mDepthIndex; }
+
+  /**
    * @brief Tells if the node is a batch parent
    * @return True if node is a batch parent, false otherwise.
    */
@@ -887,10 +894,11 @@ protected:
   CollectedUniformMap                mCollectedUniformMap[2]; ///< Uniform maps of the node
   unsigned int                       mUniformMapChanged[2];   ///< Records if the uniform map has been altered this frame
   uint32_t                           mClippingDepth;          ///< The number of clipping nodes deep this node is
-  unsigned int                       mRegenerateUniformMap:2; ///< Indicate if the uniform map has to be regenerated this frame
+
+  uint32_t                           mDepthIndex;             ///< Depth index of the node
 
   // flags, compressed to bitfield
-  unsigned short                     mDepth:12;               ///< Depth in the hierarchy
+  unsigned int                       mRegenerateUniformMap:2; ///< Indicate if the uniform map has to be regenerated this frame
   int                                mDirtyFlags:8;           ///< A composite set of flags for each of the Node properties
   DrawMode::Type                     mDrawMode:2;             ///< How the Node and its children should be drawn
   ColorMode                          mColorMode:2;            ///< Determines whether mWorldColor is inherited, 2 bits is enough
@@ -1013,6 +1021,17 @@ inline void SetIsBatchParentMessage( EventThreadServices& eventThreadServices, c
   new (slot) LocalType( &node, &Node::SetIsBatchParent, isBatchParent );
 }
 
+inline void SetDepthIndexMessage( EventThreadServices& eventThreadServices, const Node& node, unsigned int depthIndex )
+{
+  typedef MessageValue1< Node, unsigned int > LocalType;
+
+  // Reserve some memory inside the message queue
+  unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &node, &Node::SetDepthIndex, depthIndex );
+}
+
 inline void SetClippingModeMessage( EventThreadServices& eventThreadServices, const Node& node, ClippingMode::Type clippingMode )
 {
   typedef MessageValue1< Node, ClippingMode::Type > LocalType;