Hit-test can hit more than 32 depth clipping actor. 76/272976/4
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 29 Mar 2022 02:54:24 +0000 (11:54 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Fri, 1 Apr 2022 12:56:51 +0000 (21:56 +0900)
When clipping mode is CLIP_TO_BOUNDING_BOX, the limitation of
clipping depth doesn't exist. We can clipping near 2^15-depth.
But current clipping algorithm only allow 31-depth of clipping.

This patch make that we don't use depthmask in hit-test algorithm
When clipping mode is enabled, and current actor hit test failed,
just skip all children's hit test.

Note : CLIP_CHILDREN is kind of rendering method, So when clipping mode is
CLIP_CHILDREN, we can't detect how it "really" clipped.
This is physically limitation, so just ignore it.

Change-Id: I83524d6f96ccbb59d7b2802f1630c7e338b251a0
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp
dali/internal/event/events/hit-test-algorithm-impl.cpp

index 2229015..cea3e03 100644 (file)
@@ -324,6 +324,70 @@ int UtcDaliHitTestAlgorithmClippingActor(void)
   END_TEST;
 }
 
+int UtcDaliHitTestAlgorithmClippingActorStress(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with many many stencil");
+
+  Stage stage     = Stage::GetCurrent();
+  Actor rootLayer = stage.GetRootLayer();
+  rootLayer.SetProperty(Actor::Property::NAME, "RootLayer");
+
+  // Create a layer
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  layer.SetProperty(Actor::Property::NAME, "layer");
+  stage.Add(layer);
+
+  // Create a clipping actor and add it to the layer.
+  Actor clippingActor = CreateRenderableActor();
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+  clippingActor.SetProperty(Actor::Property::NAME, "clippingActor");
+  layer.Add(clippingActor);
+
+  // Create a renderable actor and add it to the clipping actor.
+  Actor     latestActor = clippingActor;
+  const int depthMax    = 100;
+  for(int i = 0; i < depthMax; i++)
+  {
+    char tmp[29];
+    sprintf(tmp, "depth%03d", i);
+
+    Actor childActor = CreateRenderableActor();
+    childActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+    childActor.SetProperty(Actor::Property::POSITION, Vector2(200.0f / depthMax, 200.0f / depthMax));
+    childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+    childActor.SetProperty(Actor::Property::NAME, tmp);
+
+    latestActor.Add(childActor);
+    latestActor = childActor;
+  }
+  // NOTE : latestActor's TOP_LEFT position become 200.f, 200.0f
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Hit within clippingActor and latestActor.
+  HitTestAlgorithm::Results results;
+  HitTest(stage, Vector2(201.0f, 201.0f), results, &DefaultIsActorTouchableFunction);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == latestActor);
+
+  // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
+  HitTest(stage, Vector2(221.0f, 221.0f), results, &DefaultIsActorTouchableFunction);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == rootLayer);
+
+  END_TEST;
+}
+
 int UtcDaliHitTestAlgorithmOverlay(void)
 {
   TestApplication application;
index 267c1ff..0ed24be 100644 (file)
@@ -167,8 +167,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                             const bool&                                overlayed,
                             bool&                                      overlayHit,
                             bool                                       layerIs3d,
-                            uint32_t                                   clippingDepth,
-                            uint32_t                                   clippingBitPlaneMask,
                             const RayTest&                             rayTest,
                             const Integration::Point&                  point,
                             const uint32_t                             eventTime)
@@ -180,17 +178,11 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
     return hit;
   }
 
-  // For clipping, regardless of whether we have hit this actor or not,
-  // we increase the clipping depth if we have hit a clipping actor.
+  // For clipping, regardless of whether we have hit this actor or not.
   // This is used later to ensure all nested clipped children have hit
   // all clipping actors also for them to be counted as hit.
-  uint32_t newClippingDepth = clippingDepth;
-  bool     clippingActor    = actor.GetClippingMode() != ClippingMode::DISABLED;
-  bool     overlayedActor   = overlayed || actor.IsOverlay();
-  if(clippingActor)
-  {
-    ++newClippingDepth;
-  }
+  bool clippingActor  = actor.GetClippingMode() != ClippingMode::DISABLED;
+  bool overlayedActor = overlayed || actor.IsOverlay();
 
   // If we are a clipping actor or hittable...
   if(clippingActor || hitCheck.IsActorHittable(&actor))
@@ -215,13 +207,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
         // Check if cameraDepthDistance is between clipping plane
         if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= farClippingPlane)
         {
-          // If the hit has happened on a clipping actor, then add this clipping depth to the mask of hit clipping depths.
-          // This mask shows all the actors that have been hit at different clipping depths.
-          if(clippingActor)
-          {
-            clippingBitPlaneMask |= 1u << clippingDepth;
-          }
-
           if(overlayHit && !overlayedActor)
           {
             // If we have already hit an overlay and current actor is not an overlay ignore current actor.
@@ -233,34 +218,8 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
               overlayHit = true;
             }
 
-            // At this point we have hit an actor.
-            // Now perform checks for clipping.
-            // Assume we have hit the actor first as if it is not clipped this would be the case.
-            bool haveHitActor = true;
-
-            // Check if we are performing clipping. IE. if any actors so far have clipping enabled - not necessarily this one.
-            // We can do this by checking the clipping depth has a value 1 or above.
-            if(newClippingDepth >= 1u)
-            {
-              // Now for us to count this actor as hit, we must have also hit
-              // all CLIPPING actors up to this point in the hierarchy as well.
-              // This information is stored in the clippingBitPlaneMask we updated above.
-              // Here we calculate a comparison mask by setting all the bits up to the current depth value.
-              // EG. a depth of 4 (10000 binary) = a mask of 1111 binary.
-              // This allows us a fast way of comparing all bits are set up to this depth.
-              // Note: If the current Actor has clipping, that is included in the depth mask too.
-              uint32_t clippingDepthMask = (1u << newClippingDepth) - 1u;
-
-              // The two masks must be equal to be a hit, as we are already assuming a hit
-              // (for non-clipping mode) then they must be not-equal to disqualify the hit.
-              if(clippingBitPlaneMask != clippingDepthMask)
-              {
-                haveHitActor = false;
-              }
-            }
-
             // If the hit actor does not want to hit, the hit-test continues.
-            if(haveHitActor && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
+            if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -288,6 +247,12 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
     }
   }
 
+  // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
+  if(clippingActor && !(hit.actor))
+  {
+    return hit;
+  }
+
   // Find a child hit, until we run out of actors in the current layer.
   HitActor childHit;
   if(actor.GetChildCount() > 0)
@@ -316,8 +281,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                                                overlayedActor,
                                                overlayHit,
                                                layerIs3d,
-                                               newClippingDepth,
-                                               clippingBitPlaneMask,
                                                rayTest,
                                                point,
                                                eventTime));
@@ -505,8 +468,6 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        overlayHit,
                                        overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
                                        rayTest,
                                        results.point,
                                        results.eventTime);
@@ -525,8 +486,6 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        overlayHit,
                                        overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
                                        rayTest,
                                        results.point,
                                        results.eventTime);