Fix scissor clipping issue 93/250593/1
authorHeeyong Song <heeyong.song@samsung.com>
Wed, 30 Dec 2020 04:25:45 +0000 (13:25 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Wed, 30 Dec 2020 04:25:45 +0000 (13:25 +0900)
- Should consider y-axis inversion for the scissor box

Change-Id: I27d3e0842d0095198caf243d80ce2b2af6825750

automated-tests/src/dali/utc-Dali-RenderTask.cpp
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/common/render-algorithms.h
dali/internal/update/render-tasks/scene-graph-camera.h

index d60bc54..e58f206 100644 (file)
@@ -184,16 +184,18 @@ RenderTask CreateRenderTask(TestApplication& application,
                             Actor            rootActor,       // Reset default render task to point at this actor
                             Actor            secondRootActor, // Source actor
                             unsigned int     refreshRate,
-                            bool             glSync)
+                            bool             glSync,
+                            uint32_t         frameBufferWidth  = 10,
+                            uint32_t         frameBufferHeight = 10)
 {
   // Change main render task to use a different root
   RenderTaskList taskList = application.GetScene().GetRenderTaskList();
   taskList.GetTask(0u).SetSourceActor(rootActor);
 
-  FrameBuffer frameBuffer = FrameBuffer::New(10, 10);
+  FrameBuffer frameBuffer = FrameBuffer::New(frameBufferWidth, frameBufferHeight);
   if(glSync)
   {
-    NativeImageInterfacePtr testNativeImagePtr = TestNativeImage::New(10, 10);
+    NativeImageInterfacePtr testNativeImagePtr = TestNativeImage::New(frameBufferWidth, frameBufferHeight);
     Texture                 texture            = Texture::New(*testNativeImagePtr);
     frameBuffer.AttachColorTexture(texture);
   }
@@ -3357,3 +3359,118 @@ int UtcDaliRenderTaskGetScreenToFrameBufferMappingActorNegative(void)
   }
   END_TEST;
 }
+
+int UtcDaliRenderTaskClippingMode01(void)
+{
+  TestApplication application;
+
+  tet_infoline("Testing clipping mode: CLIP_TO_BOUNDING_BOX.\n");
+
+  TestGlAbstraction& glAbstraction       = application.GetGlAbstraction();
+  TraceCallStack&    enabledDisableTrace = glAbstraction.GetEnableDisableTrace();
+  TraceCallStack&    scissorTrace        = glAbstraction.GetScissorTrace();
+
+  enabledDisableTrace.Enable(true);
+  scissorTrace.Enable(true);
+
+  // SETUP AN OFFSCREEN RENDER TASK
+  Actor rootActor = Actor::New();
+  application.GetScene().Add(rootActor);
+
+  CameraActor offscreenCameraActor = CameraActor::New(Size(TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT));
+  offscreenCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  offscreenCameraActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  application.GetScene().Add(offscreenCameraActor);
+
+  Shader     shader     = CreateShader();
+  Texture    image      = CreateTexture();
+  TextureSet textureSet = CreateTextureSet(image);
+
+  Geometry geometry = CreateQuadGeometry();
+  Renderer renderer = Renderer::New(geometry, shader);
+  renderer.SetTextures(textureSet);
+
+  Vector2 position(100.0f, 100.0f);
+  Vector2 size(200.0f, 200.0f);
+  Actor   secondRootActor = Actor::New();
+  secondRootActor.AddRenderer(renderer);
+  secondRootActor.SetProperty(Actor::Property::POSITION, position);
+  secondRootActor.SetProperty(Actor::Property::SIZE, size);
+  secondRootActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  secondRootActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  secondRootActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+  application.GetScene().Add(secondRootActor);
+
+  RenderTask newTask = CreateRenderTask(application, offscreenCameraActor, rootActor, secondRootActor, RenderTask::REFRESH_ONCE, true, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(enabledDisableTrace.FindMethodAndParams("Enable", "3089")); // 3089 = 0xC11 (GL_SCISSOR_TEST)
+
+  // Check the scissor was set, and the coordinates are correct.
+  Vector4           expectResults(position.x, TestApplication::DEFAULT_SURFACE_HEIGHT - size.height - position.y, size.width, size.height); // (100, 500, 200, 200)
+  std::stringstream compareParametersString;
+  compareParametersString << expectResults.x << ", " << expectResults.y << ", " << expectResults.z << ", " << expectResults.w;
+  DALI_TEST_CHECK(scissorTrace.FindMethodAndParams("Scissor", compareParametersString.str())); // Compare with the expected result
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskClippingMode02(void)
+{
+  TestApplication application;
+
+  tet_infoline("Testing clipping mode with the inverted camera: CLIP_TO_BOUNDING_BOX.\n");
+
+  TestGlAbstraction& glAbstraction       = application.GetGlAbstraction();
+  TraceCallStack&    enabledDisableTrace = glAbstraction.GetEnableDisableTrace();
+  TraceCallStack&    scissorTrace        = glAbstraction.GetScissorTrace();
+
+  enabledDisableTrace.Enable(true);
+  scissorTrace.Enable(true);
+
+  // SETUP AN OFFSCREEN RENDER TASK
+  Actor rootActor = Actor::New();
+  application.GetScene().Add(rootActor);
+
+  CameraActor offscreenCameraActor = CameraActor::New(Size(TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT));
+  offscreenCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  offscreenCameraActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  offscreenCameraActor.SetInvertYAxis(true);
+  application.GetScene().Add(offscreenCameraActor);
+
+  Shader     shader     = CreateShader();
+  Texture    image      = CreateTexture();
+  TextureSet textureSet = CreateTextureSet(image);
+
+  Geometry geometry = CreateQuadGeometry();
+  Renderer renderer = Renderer::New(geometry, shader);
+  renderer.SetTextures(textureSet);
+
+  Vector2 position(100.0f, 100.0f);
+  Vector2 size(200.0f, 200.0f);
+  Actor   secondRootActor = Actor::New();
+  secondRootActor.AddRenderer(renderer);
+  secondRootActor.SetProperty(Actor::Property::POSITION, position);
+  secondRootActor.SetProperty(Actor::Property::SIZE, size);
+  secondRootActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  secondRootActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  secondRootActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+  application.GetScene().Add(secondRootActor);
+
+  RenderTask newTask = CreateRenderTask(application, offscreenCameraActor, rootActor, secondRootActor, RenderTask::REFRESH_ONCE, true, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(enabledDisableTrace.FindMethodAndParams("Enable", "3089")); // 3089 = 0xC11 (GL_SCISSOR_TEST)
+
+  // Check the scissor was set, and the coordinates are correct.
+  Vector4           expectResults(position.x, position.y, size.width, size.height); // (100, 100, 200, 200)
+  std::stringstream compareParametersString;
+  compareParametersString << expectResults.x << ", " << expectResults.y << ", " << expectResults.z << ", " << expectResults.w;
+  DALI_TEST_CHECK(scissorTrace.FindMethodAndParams("Scissor", compareParametersString.str())); // Compare with the expected result
+
+  END_TEST;
+}
index 314a974..fc1c0c1 100755 (executable)
@@ -223,15 +223,15 @@ inline void SetupDepthBuffer( const RenderItem& item, Context& context, bool dep
 
 } // Unnamed namespace
 
-
 /**
  * @brief This method is responsible for making decisions on when to apply and unapply scissor clipping, and what rectangular dimensions should be used.
  * A stack of scissor clips at each depth of clipping is maintained, so it can be applied and unapplied.
  * As the clips are hierarchical, this RenderItems AABB is clipped against the current "active" scissor bounds via an intersection operation.
  * @param[in]     item                     The current RenderItem about to be rendered
  * @param[in]     context                  The context
+ * @param[in]     instruction              The render-instruction to process.
  */
-inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Context& context )
+inline void RenderAlgorithms::SetupScissorClipping(const RenderItem& item, Context& context, const RenderInstruction& instruction)
 {
   // Get the number of child scissors in the stack (do not include layer or root box).
   size_t childStackDepth = mScissorStack.size() - 1u;
@@ -292,17 +292,23 @@ inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Cont
     if( scissorEnabled )
     {
       ClippingBox useScissorBox( mScissorStack.back() );
+
+      if(instruction.mFrameBuffer && instruction.GetCamera()->IsYAxisInverted())
+      {
+        useScissorBox.y = (instruction.mFrameBuffer->GetHeight() - useScissorBox.height) - useScissorBox.y;
+      }
       context.Scissor( useScissorBox.x, useScissorBox.y, useScissorBox.width, useScissorBox.height );
     }
   }
 }
 
-inline void RenderAlgorithms::SetupClipping( const RenderItem& item,
-                                             Context& context,
-                                             bool& usedStencilBuffer,
-                                             uint32_t& lastClippingDepth,
-                                             uint32_t& lastClippingId,
-                                             Integration::StencilBufferAvailable stencilBufferAvailable )
+inline void RenderAlgorithms::SetupClipping(const RenderItem&                   item,
+                                            Context&                            context,
+                                            bool&                               usedStencilBuffer,
+                                            uint32_t&                           lastClippingDepth,
+                                            uint32_t&                           lastClippingId,
+                                            Integration::StencilBufferAvailable stencilBufferAvailable,
+                                            const RenderInstruction&            instruction)
 {
   RenderMode::Type renderMode = RenderMode::AUTO;
   const Renderer *renderer = item.mRenderer;
@@ -324,7 +330,7 @@ inline void RenderAlgorithms::SetupClipping( const RenderItem& item,
       // As both scissor and stencil clips can be nested, we may be simultaneously traversing up the scissor tree, requiring a scissor to be un-done. Whilst simultaneously adding a new stencil clip.
       // We process both based on our current and old clipping depths for each mode.
       // Both methods with return rapidly if there is nothing to be done for that type of clipping.
-      SetupScissorClipping( item, context );
+      SetupScissorClipping(item, context, instruction);
 
       if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE )
       {
@@ -462,7 +468,7 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
 
     // Set up clipping based on both the Renderer and Actor APIs.
     // The Renderer API will be used if specified. If AUTO, the Actors automatic clipping feature will be used.
-    SetupClipping( item, context, usedStencilBuffer, lastClippingDepth, lastClippingId, stencilBufferAvailable );
+    SetupClipping(item, context, usedStencilBuffer, lastClippingDepth, lastClippingId, stencilBufferAvailable, instruction);
 
     if( DALI_LIKELY( item.mRenderer ) )
     {
index 9d359b4..d0d90fe 100644 (file)
@@ -86,10 +86,11 @@ class RenderAlgorithms
      *  - If the node is a clipping node, apply the nodes clip intersected with the current/parent scissor clip.
      *  - If we have gone up the scissor hierarchy, and need to un-apply a scissor clip.
      *  - Disable scissor clipping completely if it is not needed
-     * @param[in] item     The current RenderItem (about to be rendered)
-     * @param[in] context  The current Context
+     * @param[in] item        The current RenderItem (about to be rendered)
+     * @param[in] context     The current Context
+     * @param[in] instruction The render-instruction to process.
      */
-    inline void SetupScissorClipping( const Dali::Internal::SceneGraph::RenderItem& item, Context& context );
+    inline void SetupScissorClipping(const Dali::Internal::SceneGraph::RenderItem& item, Context& context, const Dali::Internal::SceneGraph::RenderInstruction& instruction);
 
     /**
      * @brief Set up the clipping based on the specified clipping settings.
@@ -99,13 +100,15 @@ class RenderAlgorithms
      * @param[in/out] lastClippingDepth        The stencil depth of the last renderer drawn. Used by the clipping feature.
      * @param[in/out] lastClippingId           The clipping ID of the last renderer drawn.   Used by the clipping feature.
      * @param[in]     stencilBufferAvailable   Whether the stencil buffer is available
+     * @param[in]     instruction              The render-instruction to process.
      */
-    inline void SetupClipping( const Dali::Internal::SceneGraph::RenderItem& item,
-                               Context& context,
-                               bool& usedStencilBuffer,
-                               uint32_t& lastClippingDepth,
-                               uint32_t& lastClippingId,
-                               Integration::StencilBufferAvailable stencilBufferAvailable );
+    inline void SetupClipping(const Dali::Internal::SceneGraph::RenderItem&        item,
+                              Context&                                             context,
+                              bool&                                                usedStencilBuffer,
+                              uint32_t&                                            lastClippingDepth,
+                              uint32_t&                                            lastClippingId,
+                              Integration::StencilBufferAvailable                  stencilBufferAvailable,
+                              const Dali::Internal::SceneGraph::RenderInstruction& instruction);
 
     /**
      * @brief Process a render-list.
index d752b5c..a5db970 100644 (file)
@@ -116,6 +116,15 @@ public:
   void SetInvertYAxis( bool invertYAxis );
 
   /**
+   * Returns whether the Y axis is inverted.
+   * @return True if the Y axis is inverted, false otherwise.
+   */
+  bool IsYAxisInverted() const
+  {
+    return mInvertYAxis;
+  }
+
+  /**
    * @copydoc Dali::Internal::CameraActor::SetProjectionMode
    */
   void SetProjectionMode( Dali::Camera::ProjectionMode projectionMode );