Allow to create renderer without geometry and shader 98/320698/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 6 Mar 2025 04:28:51 +0000 (13:28 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 6 Mar 2025 07:03:27 +0000 (16:03 +0900)
Let we make constructor renderer without geometry and shader.

Also, check some codes s.t. we can allow nullptr mGeometry and mShader.

Change-Id: I99eb3011c4cb7f1a3c9ff69f90842c44005048f6
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali/utc-Dali-DrawableActor.cpp
automated-tests/src/dali/utc-Dali-Renderer.cpp
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/rendering/scene-graph-renderer.h
dali/public-api/rendering/renderer.cpp
dali/public-api/rendering/renderer.h

index f200991f2b01418e8232b51779dfa63ffbcd5fd4..00da72cfe7185fb837a54bd174bceb0097616952 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -69,6 +69,10 @@ int UtcDaliRendererSetRenderCallbackP(void)
   auto size(drawable.size);
   DALI_TEST_EQUALS(drawable.size, Size(100, 100), TEST_LOCATION);
 
+  // render once again, for line coverage
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
index cd55bd6946b9f202f6550addbc603d016fbc9ad7..7b15104748e163c2930cc6b83f7bde9db6a3b6fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -140,6 +140,19 @@ int UtcDaliRendererNew02(void)
   END_TEST;
 }
 
+int UtcDaliRendererNew03(void)
+{
+  TestApplication application;
+
+  Renderer renderer = Renderer::New();
+  DALI_TEST_EQUALS((bool)renderer, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(!!renderer.GetGeometry(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!renderer.GetShader(), false, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliRendererCopyConstructor(void)
 {
   TestApplication application;
@@ -412,6 +425,147 @@ int UtcDaliRendererSetGetShader(void)
   END_TEST;
 }
 
+int UtcDaliRendererSetGetGeometryAndShader01(void)
+{
+  TestApplication application;
+  tet_infoline("Test SetGeometry, GetGeometry, SetShader, GetShader without new creation.");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableCullFaceCallTrace(true);
+
+  Shader shader1 = CreateShader();
+  shader1.RegisterProperty("uFadeColor", Color::RED);
+
+  Shader shader2 = CreateShader();
+  shader2.RegisterProperty("uFadeColor", Color::GREEN);
+
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer renderer = Renderer::New();
+  Actor    actor    = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  TestGlAbstraction& gl        = application.GetGlAbstraction();
+  TraceCallStack&    drawTrace = gl.GetDrawTrace();
+
+  DALI_TEST_EQUALS(!!renderer.GetGeometry(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!renderer.GetShader(), false, TEST_LOCATION);
+
+  drawTrace.Enable(true);
+  drawTrace.Reset();
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Nothing rendered!
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawElements"));
+  drawTrace.Reset();
+
+  // Set geometry after rendering.
+  renderer.SetGeometry(geometry);
+  DALI_TEST_EQUALS(renderer.GetGeometry(), geometry, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!renderer.GetShader(), false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Also rendering skipped.
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawElements"));
+  drawTrace.Reset();
+
+  // Set shader after rendering.
+  renderer.SetShader(shader1);
+  DALI_TEST_EQUALS(renderer.GetGeometry(), geometry, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetShader(), shader1, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Expect that the first shaders's fade color property is accessed
+  Vector4 actualValue(Vector4::ZERO);
+  DALI_TEST_CHECK(drawTrace.FindMethod("DrawElements"));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>("uFadeColor", actualValue));
+  DALI_TEST_EQUALS(actualValue, Color::RED, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(renderer.GetShader(), shader1, TEST_LOCATION);
+
+  // set the second shader to the renderer
+  renderer.SetShader(shader2);
+  DALI_TEST_EQUALS(renderer.GetGeometry(), geometry, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetShader(), shader2, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Expect that the second shader's fade color property is accessed
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>("uFadeColor", actualValue));
+  DALI_TEST_EQUALS(actualValue, Color::GREEN, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(renderer.GetShader(), shader2, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliRendererSetGetGeometryAndShader02(void)
+{
+  TestApplication application;
+  tet_infoline("Test SetGeometry, GetGeometry, SetShader, GetShader without new creation.");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableCullFaceCallTrace(true);
+
+  Shader   shader   = CreateShader();
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer renderer = Renderer::New();
+  Actor    actor    = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  TestGlAbstraction& gl        = application.GetGlAbstraction();
+  TraceCallStack&    drawTrace = gl.GetDrawTrace();
+
+  DALI_TEST_EQUALS(!!renderer.GetGeometry(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!renderer.GetShader(), false, TEST_LOCATION);
+
+  drawTrace.Enable(true);
+  drawTrace.Reset();
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Nothing rendered!
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawElements"));
+  drawTrace.Reset();
+
+  // Set shader after rendering.
+  renderer.SetShader(shader);
+  DALI_TEST_EQUALS(!!renderer.GetGeometry(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetShader(), shader, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Also rendering skipped.
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawElements"));
+  drawTrace.Reset();
+
+  // Set geometry after rendering.
+  renderer.SetGeometry(geometry);
+  DALI_TEST_EQUALS(renderer.GetGeometry(), geometry, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetShader(), shader, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_CHECK(drawTrace.FindMethod("DrawElements"));
+
+  END_TEST;
+}
+
 int UtcDaliRendererSetGetDepthIndex(void)
 {
   TestApplication application;
index 8fc3459fb30f8ce257a8ab35d4bb807155c85ae6..33204802e44933742ebb1231588ef260c066d088 100644 (file)
@@ -495,7 +495,7 @@ inline void RenderAlgorithms::SetupScissorClipping(
   {
     // If there is render callback on the Renderer we need to calculate the scissor box and provide it to the
     // callback so it may be clipped
-    if(item.mRenderer->GetRenderCallback())
+    if(DALI_LIKELY(item.mRenderer) && item.mRenderer->GetRenderCallback())
     {
       // store clipping box inside the render callback input structure
       auto& input       = item.mRenderer->GetRenderCallbackInput();
index e6a752aaa6cc7ba0c0d6b9006e2190baae9d6fe0..eea7133dd60f0ea3db8b2c9939fdf454abd90a9f 100644 (file)
@@ -415,11 +415,6 @@ StencilOperation::Type Renderer::GetStencilOperationOnZPass() const
   return mStencilParameters.stencilOperationOnZPass;
 }
 
-void Renderer::Upload()
-{
-  mGeometry->Upload(*mGraphicsController);
-}
-
 bool Renderer::NeedsProgram() const
 {
   // Our access to shader is currently through the RenderDataProvider, which
@@ -587,6 +582,12 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
     return true;
   }
 
+  if(DALI_UNLIKELY(!mGeometry))
+  {
+    // Geometry not set. Ignore below logics.
+    return false;
+  }
+
   // Prepare commands
   std::vector<DevelRenderer::DrawCommand*> commands;
   for(auto& cmd : mDrawCommands)
@@ -983,8 +984,16 @@ void Renderer::WriteDynUniform(
 
 void Renderer::SetSortAttributes(SceneGraph::RenderInstructionProcessor::SortAttributes& sortAttributes) const
 {
-  sortAttributes.shader   = &mRenderDataProvider->GetShader();
-  sortAttributes.geometry = mGeometry;
+  if(!mRenderCallback)
+  {
+    sortAttributes.shader   = &mRenderDataProvider->GetShader();
+    sortAttributes.geometry = mGeometry;
+  }
+  else
+  {
+    sortAttributes.shader   = nullptr;
+    sortAttributes.geometry = nullptr;
+  }
 }
 
 void Renderer::SetShaderChanged(bool value)
@@ -994,7 +1003,7 @@ void Renderer::SetShaderChanged(bool value)
 
 bool Renderer::Updated()
 {
-  if(mRenderCallback || mShaderChanged || mGeometry->Updated() || mRenderDataProvider->IsUpdated())
+  if(mRenderCallback || mShaderChanged || (DALI_LIKELY(mGeometry) && mGeometry->Updated()) || mRenderDataProvider->IsUpdated())
   {
     return true;
   }
@@ -1148,6 +1157,8 @@ Graphics::Pipeline& Renderer::PrepareGraphicsPipeline(
   const SceneGraph::NodeDataProvider&                  node,
   bool                                                 blend)
 {
+  DALI_ASSERT_DEBUG(mGeometry && "Geometry should not be nullptr! something wrong!\n");
+
   // Prepare query info
   PipelineCacheQueryInfo queryInfo{};
   queryInfo.program               = &program;
index d994c2c66e8e33175757e95ca22633e34ebfba77..d8da43a0b14688a1f0b1f8404ae01eafe8ff61b5 100644 (file)
@@ -395,11 +395,6 @@ public:
    */
   [[nodiscard]] StencilOperation::Type GetStencilOperationOnZPass() const;
 
-  /**
-   * Called to upload during RenderManager::Render().
-   */
-  void Upload();
-
   /**
    * Called to render during RenderManager::Render().
    * @param[in,out] commandBuffer The command buffer to write into
index 16c1625aabec9a6120ab8d96738082cd14ec2701..6bd40e50c959d43a9725a367666a652f458ed840 100644 (file)
@@ -181,7 +181,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 
   auto& nodePartialRenderingData = node->GetPartialRenderingData();
 
-  const bool rendererExist(renderable.mRenderer);
+  const bool rendererExist(renderable.mRenderer && DALI_LIKELY(renderable.mRenderer->IsRenderable()));
 
   // Don't cull items which have render callback
   bool hasRenderCallback = (rendererExist && renderable.mRenderer->GetRenderCallback());
index 46e9ebec610e1d07123131cf3d47e77c5177ed54..252f0dd61f8457436072ba4ffe03215fddeaf46e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_RENDERER_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -509,6 +509,14 @@ public:
    */
   void RequestResetToBaseValues();
 
+  /**
+   * @brief True if this renderer could be renderable. False otherwise.
+   */
+  bool IsRenderable() const
+  {
+    return (mGeometry && mShader) || mRenderCallback;
+  }
+
   /**
    * Get the capacity of the memory pools
    * @return the capacity of the memory pools
index 90cb94e1319992a8e7b16d742a43135efa046606..71155955d0bc826d867fdceea9868ed1baaeafd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -38,6 +38,12 @@ Renderer Renderer::New(RenderCallback& renderCallback)
   return Renderer(renderer.Get());
 }
 
+Renderer Renderer::New()
+{
+  Internal::RendererPtr renderer = Internal::Renderer::New();
+  return Renderer(renderer.Get());
+}
+
 Renderer::Renderer() = default;
 
 Renderer::~Renderer() = default;
index 217ca617a424dff9a5368885cd5b96f35e502e69..26fb79e8d4564cf0324cae3a944e013f62c23201 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_RENDERER_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -473,6 +473,15 @@ public:
    */
   static Renderer New(RenderCallback& renderCallback);
 
+  /**
+   * @brief Creates a new Renderer object without geometry and shader.
+   * @post We should set Geometry and Shader before attach to actor. If not, exception throwed.
+   *
+   * @SINCE_2_4.9
+   * @return A handle to the Renderer
+   */
+  static Renderer New();
+
   /**
    * @brief Default constructor, creates an empty handle
    *