[Tizen] Support multi pass shading with different shaders 15/296815/3
authorseungho baek <sbsh.baek@samsung.com>
Fri, 9 Jun 2023 13:00:09 +0000 (22:00 +0900)
committerseungho baek <sbsh.baek@samsung.com>
Wed, 23 Aug 2023 04:46:29 +0000 (13:46 +0900)
Change-Id: I34ac0d2dd0d63b316816bfa58954c739e7460e55
Signed-off-by: seungho baek <sbsh.baek@samsung.com>
22 files changed:
automated-tests/src/dali/utc-Dali-RenderTask.cpp
automated-tests/src/dali/utc-Dali-Shader.cpp
dali/internal/common/shader-data.h
dali/internal/event/effects/shader-factory.cpp
dali/internal/event/effects/shader-factory.h
dali/internal/event/render-tasks/render-task-impl.cpp
dali/internal/event/render-tasks/render-task-impl.h
dali/internal/event/rendering/shader-impl.cpp
dali/internal/event/rendering/shader-impl.h
dali/internal/render/common/render-instruction.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/shaders/render-shader.cpp
dali/internal/render/shaders/render-shader.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h
dali/public-api/render-tasks/render-task.cpp
dali/public-api/render-tasks/render-task.h
dali/public-api/rendering/shader.cpp
dali/public-api/rendering/shader.h

index e3857dc..79cb0ed 100644 (file)
@@ -78,10 +78,74 @@ void utc_dali_render_task_cleanup(void)
  * FinishedSignal                      1+ve
  */
 
-namespace // unnamed namespace
+namespace                             // unnamed namespace
 {
 const int RENDER_FRAME_INTERVAL = 16; ///< Duration of each frame in ms. (at approx 60FPS)
 
+// Test shader codes
+const std::string_view SHADER_COLOR_TEST_SHADER_VERT1{
+  R"(INPUT mediump vec2 aPosition;
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+uniform mediump vec2 extraSize;
+
+vec4 ComputeVertexPosition()
+{
+  vec2 visualSize = mix(size * uSize.xy, size, offsetSizeMode.zw ) + extraSize;
+  vec2 visualOffset = mix(offset * uSize.xy, offset, offsetSizeMode.xy);
+  mediump vec2 vPosition = aPosition * visualSize;
+  return vec4(vPosition + anchorPoint * visualSize + visualOffset + origin * uSize.xy, 0.0, 1.0);
+}
+
+void main()
+{
+  gl_Position = uMvpMatrix * ComputeVertexPosition();
+}
+)"};
+
+// Test shader codes
+const std::string_view SHADER_COLOR_TEST_SHADER_VERT2{
+  R"(INPUT mediump vec2 aPosition;
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+uniform mediump vec2 extraSize;
+
+vec4 ComputeVertexPosition2()
+{
+  vec2 visualSize = mix(size * uSize.xy, size, offsetSizeMode.zw ) + extraSize;
+  vec2 visualOffset = mix(offset * uSize.xy, offset, offsetSizeMode.xy);
+  mediump vec2 vPosition = aPosition * visualSize;
+  return vec4(vPosition + anchorPoint * visualSize + visualOffset + origin * uSize.xy, 0.0, 1.0);
+}
+
+void main()
+{
+  gl_Position = uMvpMatrix * ComputeVertexPosition2();
+}
+)"};
+
+const std::string_view SHADER_COLOR_TEST_SHADER_FRAG{
+  R"(
+void main()
+{
+  OUT_COLOR = vec4(0.0, 0.0, 1.0, 1.0);
+}
+)"};
+
 /*
  * Simulate time passed by.
  *
@@ -2432,12 +2496,12 @@ int UtcDaliRenderTaskOnceChain01(void)
 
   application.SendNotification();
 
-  //Both render tasks are executed.
+  // Both render tasks are executed.
   DALI_TEST_CHECK(UpdateRender(application, drawTrace, true, firstFinished, false, true, __LINE__));
   DALI_TEST_CHECK(firstFinished == false);
   DALI_TEST_CHECK(secondFinished == false);
 
-  //Nothing else to render and both render task should have finished now
+  // Nothing else to render and both render task should have finished now
   DALI_TEST_CHECK(UpdateRender(application, drawTrace, false, firstFinished, true, false, __LINE__));
   DALI_TEST_CHECK(firstFinished == true);
   DALI_TEST_CHECK(secondFinished == true);
@@ -3683,3 +3747,453 @@ int UtcDaliRenderTaskViewportGuideActor02(void)
 
   END_TEST;
 }
+
+int UtcDaliRenderTaskViewportGuideActor03(void)
+{
+  TestApplication application(
+    TestApplication::DEFAULT_SURFACE_WIDTH,
+    TestApplication::DEFAULT_SURFACE_HEIGHT,
+    TestApplication::DEFAULT_HORIZONTAL_DPI,
+    TestApplication::DEFAULT_VERTICAL_DPI,
+    true,
+    true);
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack&    callStack     = glAbstraction.GetViewportTrace();
+  glAbstraction.EnableViewportCallTrace(true);
+  tet_infoline("Testing that adding a viewport guide actor to RenderTask will change the viewport");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  glAbstraction.ResetViewportCallStack();
+
+  Geometry geometry = Geometry::New();
+  Shader   shader   = Shader::New("vertexSrc", "fragmentSrc");
+  Renderer renderer = Renderer::New(geometry, shader);
+
+  Actor blue                                 = Actor::New();
+  blue[Dali::Actor::Property::NAME]          = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::TOP_LEFT;
+  blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
+  blue[Dali::Actor::Property::SIZE]          = Vector2(400, 300);
+  blue[Dali::Actor::Property::POSITION]      = Vector2(100, 50);
+  blue.AddRenderer(renderer);
+  stage.Add(blue);
+
+  Actor green                                 = Actor::New();
+  green[Dali::Actor::Property::NAME]          = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::TOP_LEFT;
+  green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
+  green[Dali::Actor::Property::SIZE]          = Vector2(400, 300);
+  green[Dali::Actor::Property::POSITION]      = Vector2(100, 50);
+  green.AddRenderer(renderer);
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     renderTask     = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  renderTask.SetExclusive(true);
+  renderTask.SetInputEnabled(true);
+  renderTask.SetCameraActor(cameraActor);
+  renderTask.SetSourceActor(green);
+
+  Viewport viewport(75, 55, 150, 250);
+  renderTask.SetViewport(viewport);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+
+  // Note Y pos: 800 - (250+55) = 495
+  std::string viewportParams1("75, 495, 150, 250");
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams1) >= 0);
+  glAbstraction.ResetViewportCallStack();
+
+  // Update to use viewport guide actor instead.
+  renderTask.SetViewportGuideActor(blue);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+
+  // Note: Y pos: 800 - (300+50) = 450
+  std::string viewportParams2("100, 450, 400, 300");
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams2) >= 0);
+  tet_infoline("Testing that removing viewport guide actor from RenderTask will revert the viewport");
+  glAbstraction.ResetViewportCallStack();
+
+  // Remove guide actor, expect that the viewport is reset to its original values
+  renderTask.SetViewportGuideActor(Actor());
+  application.SendNotification();
+  application.Render(16);
+
+  // Currently, update manager does not consider that added Resetters should cause another
+  // update; this is probably right. But, we have to then force another update for the resetter to trigger, and this will register as un-necessary in the test output.
+  //
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams1) >= 0);
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskViewportGuideActor04(void)
+{
+  TestApplication application(
+    TestApplication::DEFAULT_SURFACE_WIDTH,
+    TestApplication::DEFAULT_SURFACE_HEIGHT,
+    TestApplication::DEFAULT_HORIZONTAL_DPI,
+    TestApplication::DEFAULT_VERTICAL_DPI,
+    true,
+    true);
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack&    callStack     = glAbstraction.GetViewportTrace();
+  glAbstraction.EnableViewportCallTrace(true);
+  tet_infoline("Testing that adding a viewport guide actor to RenderTask will change the viewport");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  glAbstraction.ResetViewportCallStack();
+
+  Geometry geometry = Geometry::New();
+  Shader   shader   = Shader::New("vertexSrc", "fragmentSrc");
+  Renderer renderer = Renderer::New(geometry, shader);
+
+  Actor blue                                 = Actor::New();
+  blue[Dali::Actor::Property::NAME]          = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::TOP_LEFT;
+  blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
+  blue[Dali::Actor::Property::SIZE]          = Vector2(400, 300);
+  blue[Dali::Actor::Property::POSITION]      = Vector2(100, 50);
+  blue.AddRenderer(renderer);
+  stage.Add(blue);
+
+  Actor green                                 = Actor::New();
+  green[Dali::Actor::Property::NAME]          = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::TOP_LEFT;
+  green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
+  green[Dali::Actor::Property::SIZE]          = Vector2(400, 300);
+  green[Dali::Actor::Property::POSITION]      = Vector2(100, 50);
+  green.AddRenderer(renderer);
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     renderTask     = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  renderTask.SetExclusive(true);
+  renderTask.SetInputEnabled(true);
+  renderTask.SetCameraActor(cameraActor);
+  renderTask.SetSourceActor(green);
+
+  Viewport viewport(75, 55, 150, 250);
+  renderTask.SetViewport(viewport);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+
+  // Note Y pos: 800 - (250+55) = 495
+  std::string viewportParams1("75, 495, 150, 250");
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams1) >= 0);
+  glAbstraction.ResetViewportCallStack();
+
+  // Update to use viewport guide actor instead.
+  renderTask.SetViewportGuideActor(blue);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+
+  std::string viewportParams2("100, 450, 400, 300");
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams2) >= 0);
+  tet_infoline("Testing that removing viewport guide actor from RenderTask will revert the viewport");
+
+  glAbstraction.ResetViewportCallStack();
+
+  // Remove guide actor, expect that the viewport is reset to it's original values
+  renderTask.ResetViewportGuideActor();
+  application.SendNotification();
+  application.Render(16);
+
+  // Currently, update manager does not consider that added Resetters should cause another
+  // update; this is probably right. But, we have to then force another update for the resetter
+  // to trigger, and this will register as un-necessary in the test output.
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_CHECK(callStack.FindIndexFromMethodAndParams("Viewport", viewportParams1) >= 0);
+
+  // This should remove the baking resetters, but is again going to show up
+  // as unnecessary. Also try and figure out if we can test the dirty flags
+  // here, somehow (Can at least check the property's dirty flags in the debugger).
+  application.SendNotification();
+  application.Render(16);
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskSetPartialUpdate(void)
+{
+  TestApplication application(
+    TestApplication::DEFAULT_SURFACE_WIDTH,
+    TestApplication::DEFAULT_SURFACE_HEIGHT,
+    TestApplication::DEFAULT_HORIZONTAL_DPI,
+    TestApplication::DEFAULT_VERTICAL_DPI,
+    true,
+    true);
+
+  tet_infoline("Check the damaged rects with render task");
+
+  const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+  Actor actor = CreateRenderableActor();
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+  actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+  actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+  application.GetScene().Add(actor);
+
+  Actor rootActor = CreateRenderableActor();
+  rootActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  rootActor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+  rootActor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+  rootActor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+  application.GetScene().Add(rootActor);
+
+  CameraActor cameraActor = CameraActor::New(Size(TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT));
+  cameraActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  cameraActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  application.GetScene().Add(cameraActor);
+
+  Texture     frameBufferTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, 16, 16);
+  FrameBuffer frameBuffer        = FrameBuffer::New(frameBufferTexture.GetWidth(), frameBufferTexture.GetHeight());
+  frameBuffer.AttachColorTexture(frameBufferTexture);
+
+  // Create a RenderTask and set a framebuffer
+  RenderTaskList taskList = application.GetScene().GetRenderTaskList();
+  RenderTask     newTask  = taskList.CreateTask();
+  newTask.SetCameraActor(cameraActor);
+  newTask.SetSourceActor(rootActor);
+  newTask.SetInputEnabled(false);
+  newTask.SetClearColor(Vector4(0.f, 0.f, 0.f, 0.f));
+  newTask.SetClearEnabled(true);
+  newTask.SetExclusive(true);
+  newTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+  newTask.SetFrameBuffer(frameBuffer);
+
+  application.SendNotification();
+
+  std::vector<Rect<int>> damagedRects;
+  Rect<int>              clippingRect;
+
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+  // Full update if there is off-screen rendering
+  clippingRect = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+  // Remove framebuffer
+  newTask.SetFrameBuffer(FrameBuffer());
+
+  application.SendNotification();
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+  // Full update
+  clippingRect = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Set invalid viewport of the render task
+  newTask.SetViewportSize(Vector2(-100.0f, -100.0f));
+
+  application.SendNotification();
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+  // Full update because the camera orientation is changed
+  clippingRect = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  newTask.SetViewportSize(Vector2(0.0f, 0.0f));
+
+  // Change orientation of offscreen camera
+  cameraActor.SetProperty(Actor::Property::ORIENTATION, Quaternion(Degree(90.0f), Vector3::XAXIS));
+
+  application.SendNotification();
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+  // Full update because the camera orientation is changed
+  clippingRect = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Change camera target
+  cameraActor.SetTargetPosition(Vector3(10.0f, 10.0f, 0.0f));
+
+  application.SendNotification();
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+  // Full update because the camera is moved
+  clippingRect = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskRenderPass(void)
+{
+  TestApplication application;
+  tet_infoline("Testing RenderTask with RenderPass");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                 = Actor::New();
+  blue[Dali::Actor::Property::NAME]          = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::SIZE]          = Vector2(300, 300);
+  blue[Dali::Actor::Property::POSITION]      = Vector2(0, 0);
+
+  Geometry geometry = Geometry::New();
+
+  Property::Map map[2];
+  map[0]["vertex"]     = SHADER_COLOR_TEST_SHADER_VERT1.data();
+  map[0]["fragment"]   = SHADER_COLOR_TEST_SHADER_FRAG.data();
+  map[0]["renderPass"] = 0;
+
+  map[1]["vertex"]     = SHADER_COLOR_TEST_SHADER_VERT2.data();
+  map[1]["fragment"]   = SHADER_COLOR_TEST_SHADER_FRAG.data();
+  map[1]["renderPass"] = 1;
+
+  Property::Array array;
+  array.PushBack(map[0]);
+  array.PushBack(map[1]);
+
+  Shader   shader   = Shader::New(array);
+  Renderer renderer = Renderer::New(geometry, shader);
+  blue.AddRenderer(renderer);
+
+  stage.Add(blue);
+
+  auto& gfx = application.GetGraphicsController();
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK(gfx.mCallStack.FindMethod("CreatePipeline"));
+  gfx.mCallStack.Reset();
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+
+  renderTaskList.GetTask(0u).SetRenderPass(1u);
+  DALI_TEST_EQUALS(1u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK(gfx.mCallStack.FindMethod("CreatePipeline"));
+  gfx.mCallStack.Reset();
+  DALI_TEST_EQUALS(1u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+
+  renderTaskList.GetTask(0u).SetRenderPass(0u);
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK(!gfx.mCallStack.FindMethod("CreatePipeline"));
+  gfx.mCallStack.Reset();
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+
+  renderTaskList.GetTask(0u).SetRenderPass(1u);
+  DALI_TEST_EQUALS(1u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK(!gfx.mCallStack.FindMethod("CreatePipeline"));
+  gfx.mCallStack.Reset();
+  DALI_TEST_EQUALS(1u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskWithWrongShaderData(void)
+{
+  TestApplication application;
+  tet_infoline("Testing RenderTask with wrong shader data");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                 = Actor::New();
+  blue[Dali::Actor::Property::NAME]          = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::SIZE]          = Vector2(300, 300);
+  blue[Dali::Actor::Property::POSITION]      = Vector2(0, 0);
+
+  Geometry geometry = Geometry::New();
+
+  Shader   shader   = Shader::New(Property::Value(10.0f));
+  Renderer renderer = Renderer::New(geometry, shader);
+  blue.AddRenderer(renderer);
+
+  stage.Add(blue);
+
+  auto& gfx = application.GetGraphicsController();
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+  // Render and notify
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK(!gfx.mCallStack.FindMethod("CreatePipeline"));
+  gfx.mCallStack.Reset();
+  DALI_TEST_EQUALS(0u, renderTaskList.GetTask(0u).GetRenderPass(), TEST_LOCATION);
+
+  END_TEST;
+}
index 9d51d27..3833963 100644 (file)
@@ -44,6 +44,14 @@ static const char* FragmentSource =
   "This is a custom fragment shader\n"
   "made on purpose to look nothing like a normal fragment shader inside dali\n";
 
+static const char* VertexSource2 =
+  "This is a custom vertex shader2\n"
+  "made on purpose to look nothing like a normal vertex shader inside dali\n";
+
+static const char* FragmentSource2 =
+  "This is a custom fragment shader2\n"
+  "made on purpose to look nothing like a normal fragment shader inside dali\n";
+
 void TestConstraintNoBlue(Vector4& current, const PropertyInputContainer& inputs)
 {
   current.b = 0.0f;
@@ -64,6 +72,26 @@ int UtcDaliShaderMethodNew02(void)
 {
   TestApplication application;
 
+  Property::Map map;
+  Shader        shader = Shader::New(map);
+  DALI_TEST_EQUALS((bool)shader, true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliShaderMethodNew03(void)
+{
+  TestApplication application;
+
+  Property::Map array;
+  Shader        shader = Shader::New(array);
+  DALI_TEST_EQUALS((bool)shader, true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliShaderMethodNew04(void)
+{
+  TestApplication application;
+
   Shader shader;
   DALI_TEST_EQUALS((bool)shader, false, TEST_LOCATION);
   END_TEST;
@@ -469,3 +497,151 @@ int UtcDaliShaderProgramProperty(void)
 
   END_TEST;
 }
+
+int UtcDaliShaderPropertyValueConstructorMap(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliShaderPropertyValueConstructorMap");
+
+  std::string   hintSet = "MODIFIES_GEOMETRY";
+  Property::Map map;
+  map["vertex"]     = VertexSource;
+  map["fragment"]   = FragmentSource;
+  map["renderPass"] = 0;
+  map["hints"]      = hintSet;
+
+  Shader shader = Shader::New(map);
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::MAP);
+
+  const Property::Map* outMap = value.GetMap();
+  std::string          v      = (*outMap)["vertex"].Get<std::string>();
+  std::string          f      = (*outMap)["fragment"].Get<std::string>();
+  std::string          h      = (*outMap)["hints"].Get<std::string>();
+  int32_t              r      = (*outMap)["renderPass"].Get<int32_t>();
+
+  DALI_TEST_CHECK(v == map["vertex"].Get<std::string>());
+  DALI_TEST_CHECK(f == map["fragment"].Get<std::string>());
+  DALI_TEST_CHECK(h == map["hints"].Get<std::string>());
+  DALI_TEST_CHECK(r == map["renderPass"].Get<int32_t>());
+
+  END_TEST;
+}
+
+int UtcDaliShaderPropertyValueConstructorArray(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliShaderPropertyValueConstructorArray");
+
+  std::string   hintSet = "MODIFIES_GEOMETRY";
+  Property::Map map[2];
+  map[0]["vertex"]     = VertexSource;
+  map[0]["fragment"]   = FragmentSource;
+  map[0]["renderPass"] = 0;
+  map[0]["hints"]      = hintSet;
+
+  map[1]["vertex"]     = VertexSource2;
+  map[1]["fragment"]   = FragmentSource2;
+  map[1]["renderPass"] = 1;
+  map[1]["hints"]      = hintSet;
+
+  Property::Array array;
+  array.PushBack(map[0]);
+  array.PushBack(map[1]);
+
+  Shader shader = Shader::New(array);
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::ARRAY);
+
+  const Property::Array* outArray   = value.GetArray();
+  uint32_t               arrayCount = outArray->Size();
+  DALI_TEST_CHECK(arrayCount == 2u);
+
+  for(uint32_t i = 0; i < arrayCount; ++i)
+  {
+    const Property::Map* outMap = outArray->GetElementAt(i).GetMap();
+    std::string          v      = (*outMap)["vertex"].Get<std::string>();
+    std::string          f      = (*outMap)["fragment"].Get<std::string>();
+    std::string          h      = (*outMap)["hints"].Get<std::string>();
+    int32_t              r      = (*outMap)["renderPass"].Get<int32_t>();
+
+    DALI_TEST_CHECK(v == map[i]["vertex"].Get<std::string>());
+    DALI_TEST_CHECK(f == map[i]["fragment"].Get<std::string>());
+    DALI_TEST_CHECK(h == map[i]["hints"].Get<std::string>());
+    DALI_TEST_CHECK(r == map[i]["renderPass"].Get<int32_t>());
+  }
+
+  END_TEST;
+}
+
+int UtcDaliShaderProgramPropertyArray(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test get/set progam property array");
+
+  Shader      shader  = Shader::New("", "");
+  std::string hintSet = "MODIFIES_GEOMETRY";
+
+  Property::Map map[2];
+  map[0]["vertex"]     = VertexSource;
+  map[0]["fragment"]   = FragmentSource;
+  map[0]["renderPass"] = 0;
+  map[0]["hints"]      = hintSet;
+
+  map[1]["vertex"]     = VertexSource2;
+  map[1]["fragment"]   = FragmentSource2;
+  map[1]["renderPass"] = 1;
+  map[1]["hints"]      = hintSet;
+
+  Property::Array array;
+  array.PushBack(map[0]);
+  array.PushBack(map[1]);
+
+  shader.SetProperty(Shader::Property::PROGRAM, Property::Value(array));
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::ARRAY);
+
+  const Property::Array* outArray   = value.GetArray();
+  uint32_t               arrayCount = outArray->Size();
+  DALI_TEST_CHECK(arrayCount == 2u);
+
+  for(uint32_t i = 0; i < arrayCount; ++i)
+  {
+    const Property::Map* outMap = outArray->GetElementAt(i).GetMap();
+    std::string          v      = (*outMap)["vertex"].Get<std::string>();
+    std::string          f      = (*outMap)["fragment"].Get<std::string>();
+    std::string          h      = (*outMap)["hints"].Get<std::string>();
+    int32_t              r      = (*outMap)["renderPass"].Get<int32_t>();
+
+    DALI_TEST_CHECK(v == map[i]["vertex"].Get<std::string>());
+    DALI_TEST_CHECK(f == map[i]["fragment"].Get<std::string>());
+    DALI_TEST_CHECK(h == map[i]["hints"].Get<std::string>());
+    DALI_TEST_CHECK(r == map[i]["renderPass"].Get<int32_t>());
+  }
+
+  END_TEST;
+}
+
+int UtcDaliShaderWrongData(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test get/set wrong data");
+
+  Shader shader = Shader::New(Property::Value(1.0f));
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::ARRAY);
+
+  const Property::Array* outArray   = value.GetArray();
+  uint32_t               arrayCount = outArray->Size();
+  DALI_TEST_CHECK(arrayCount == 0u);
+
+  END_TEST;
+}
index 3d50cfa..5b69a9f 100644 (file)
@@ -61,12 +61,13 @@ public:
    * @param[in] fragmentSource Source code for fragment program
    * @param[in] hints          Hints for rendering
    */
-  ShaderData(std::string vertexSource, std::string fragmentSource, const Dali::Shader::Hint::Value hints)
+  ShaderData(std::string vertexSource, std::string fragmentSource, const Dali::Shader::Hint::Value hints, uint32_t renderPass)
   : mShaderHash(-1),
     mVertexShader(StringToVector(vertexSource)),
     mFragmentShader(StringToVector(fragmentSource)),
     mHints(hints),
-    mSourceMode(Graphics::ShaderSourceMode::TEXT)
+    mSourceMode(Graphics::ShaderSourceMode::TEXT),
+    mRenderPass(renderPass)
   {
   }
 
@@ -76,15 +77,30 @@ public:
    * @param[in] fragmentSource Source code for fragment program
    * @param[in] hints          Hints for rendering
    */
-  ShaderData(std::vector<char>& vertexSource, std::vector<char>& fragmentSource, const Dali::Shader::Hint::Value hints)
+  ShaderData(std::vector<char>& vertexSource, std::vector<char>& fragmentSource, const Dali::Shader::Hint::Value hints, uint32_t renderPass)
   : mShaderHash(-1),
     mVertexShader(vertexSource),
     mFragmentShader(fragmentSource),
     mHints(hints),
-    mSourceMode(Graphics::ShaderSourceMode::BINARY)
+    mSourceMode(Graphics::ShaderSourceMode::BINARY),
+    mRenderPass(renderPass)
   {
   }
 
+  /**
+   * Query whether a shader hint is set.
+   *
+   * @warning This method is called from Update Algorithms.
+   *
+   * @pre The shader has been initialized.
+   * @param[in] hint The hint to check.
+   * @return True if the given hint is set.
+   */
+  [[nodiscard]] bool HintEnabled(Dali::Shader::Hint::Value hint) const
+  {
+    return mHints & hint;
+  }
+
 protected:
   /**
    * Protected Destructor
@@ -216,17 +232,27 @@ public: // API
     return mSourceMode;
   }
 
+  /**
+   * Get Render Pass of shader data
+   * @return Render Pass of this shader data, Default value is 0.
+   */
+  uint32_t GetRenderPass() const
+  {
+    return mRenderPass;
+  }
+
 private:                                        // Not implemented
   ShaderData(const ShaderData& other);          ///< no copying of this object
   ShaderData& operator=(const ShaderData& rhs); ///< no copying of this object
 
-private:                                      // Data
-  std::size_t                mShaderHash;     ///< hash key created with vertex and fragment shader code
-  std::vector<char>          mVertexShader;   ///< source code for vertex program
-  std::vector<char>          mFragmentShader; ///< source code for fragment program
-  Dali::Shader::Hint::Value  mHints;          ///< take a hint
-  Dali::Vector<uint8_t>      mBuffer;         ///< buffer containing compiled binary bytecode
-  Graphics::ShaderSourceMode mSourceMode;     ///< Source mode of shader data ( text or binary )
+private:                                        // Data
+  std::size_t                mShaderHash;       ///< hash key created with vertex and fragment shader code
+  std::vector<char>          mVertexShader;     ///< source code for vertex program
+  std::vector<char>          mFragmentShader;   ///< source code for fragment program
+  Dali::Shader::Hint::Value  mHints;            ///< take a hint
+  Dali::Vector<uint8_t>      mBuffer;           ///< buffer containing compiled binary bytecode
+  Graphics::ShaderSourceMode mSourceMode;       ///< Source mode of shader data ( text or binary )
+  uint32_t                   mRenderPass{0u};   ///< Render Pass for this shader
 };
 
 } // namespace Internal
index a2e7ca4..bb1be31 100644 (file)
@@ -71,7 +71,7 @@ ShaderFactory::~ShaderFactory()
   }
 }
 
-ShaderDataPtr ShaderFactory::Load(std::string_view vertexSource, std::string_view fragmentSource, const Dali::Shader::Hint::Value hints, size_t& shaderHash)
+ShaderDataPtr ShaderFactory::Load(std::string_view vertexSource, std::string_view fragmentSource, const Dali::Shader::Hint::Value hints, uint32_t renderPass, size_t& shaderHash)
 {
   // Work out the filename for the binary that the glsl source will be compiled and linked to:
   shaderHash = CalculateHash(vertexSource.data(), fragmentSource.data());
@@ -96,7 +96,7 @@ ShaderDataPtr ShaderFactory::Load(std::string_view vertexSource, std::string_vie
   if(shaderData.Get() == nullptr)
   {
     // Allocate the structure that returns the loaded shader:
-    shaderData = new ShaderData(std::string(vertexSource), std::string(fragmentSource), hints);
+    shaderData = new ShaderData(std::string(vertexSource), std::string(fragmentSource), hints, renderPass);
     shaderData->SetHashValue(shaderHash);
     shaderData->GetBuffer().Clear();
 
index 36931d1..744f2f6 100644 (file)
@@ -59,12 +59,13 @@ public:
    *
    * @param [in] vertexSource   The vertex shader source code
    * @param [in] fragmentSource The fragment shader source code
+   * @param [in] renderPass     RenderPass the shaders are executed
    * @param [out] shaderHash    Hash key created from vertex and fragment shader code
    * @return                    ShaderData containing the source and hash value, and additionally,
    *                            a compiled shader program binary if one could be found, else an
    *                            empty binary buffer cleared to size zero.
    */
-  Internal::ShaderDataPtr Load(std::string_view vertexSource, std::string_view fragmentSource, const Dali::Shader::Hint::Value hints, size_t& shaderHash);
+  Internal::ShaderDataPtr Load(std::string_view vertexSource, std::string_view fragmentSource, const Dali::Shader::Hint::Value hints, uint32_t renderPass, size_t& shaderHash);
 
   /**
    * @brief Saves shader to memory cache and filesystem.
index a74bba0..f6fa40b 100644 (file)
@@ -495,6 +495,20 @@ bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY,
   return actor->ScreenToLocal(*this, localX, localY, viewportX, viewportY);
 }
 
+void RenderTask::SetRenderPass(uint32_t renderPass)
+{
+  if(mRenderPass != renderPass)
+  {
+    mRenderPass = renderPass;
+    SetRenderPassMessage(GetEventThreadServices(), GetRenderTaskSceneObject(), renderPass);
+  }
+}
+
+uint32_t RenderTask::GetRenderPass() const
+{
+  return mRenderPass;
+}
+
 const SceneGraph::RenderTask& RenderTask::GetRenderTaskSceneObject() const
 {
   return *static_cast<const SceneGraph::RenderTask*>(mUpdateObject);
index c859227..4b4e318 100644 (file)
@@ -103,13 +103,13 @@ public:
   CameraActor* GetCameraActor() const;
 
   /**
-    * @copydoc Dali::RenderTask::SetFrameBuffer()
-    */
+   * @copydoc Dali::RenderTask::SetFrameBuffer()
+   */
   void SetFrameBuffer(FrameBufferPtr frameBuffer);
 
   /**
-    * @copydoc Dali::RenderTask::GetFrameBuffer
-    */
+   * @copydoc Dali::RenderTask::GetFrameBuffer
+   */
   FrameBuffer* GetFrameBuffer() const;
 
   /**
@@ -253,6 +253,16 @@ public:
    */
   bool ViewportToLocal(Actor* actor, float viewportX, float viewportY, float& localX, float& localY) const;
 
+  /**
+   * @copydoc Dali::RenderTask::SetRenderPass()
+   */
+  void SetRenderPass(uint32_t renderPass);
+
+  /**
+   * @copydoc Dali::RenderTask::GetRenderPass()
+   */
+  uint32_t GetRenderPass() const;
+
 public: // Used by RenderTaskList, which owns the SceneGraph::RenderTasks
   /**
    * Retrieve the scene-graph RenderTask object.
@@ -297,7 +307,7 @@ public: // Implementation of Object
    */
   const PropertyInputImpl* GetSceneObjectInputProperty(Property::Index index) const override;
 
-public: //signals
+public: // signals
   /**
    * Query whether a Finished signal should be emitted for this render-task.
    * This should only be called by NotificationManager, before signals are emitted.
@@ -343,8 +353,8 @@ protected:
   ~RenderTask() override;
 
 private: // not copyable
-  RenderTask()                  = delete;
-  RenderTask(const RenderTask&) = delete;
+  RenderTask()                             = delete;
+  RenderTask(const RenderTask&)            = delete;
   RenderTask& operator=(const RenderTask&) = delete;
 
 private:
@@ -354,12 +364,12 @@ private:
   WeakHandle<Dali::Actor> mInputMappingActor;  /// used to mapping screen to frame buffer coordinate, not kept alive by rendertask
   RenderTaskList&         mRenderTaskList;     ///< The render task list
 
-  Vector4 mClearColor; ///< Optional clear color
+  Vector4 mClearColor;                         ///< Optional clear color
 
-  Vector2 mViewportPosition; ///< The cached viewport position
-  Vector2 mViewportSize;     ///< The cached viewport size
+  Vector2 mViewportPosition;                   ///< The cached viewport position
+  Vector2 mViewportSize;                       ///< The cached viewport size
 
-  uint32_t mRefreshRate; ///< Determines how often the task is processed.
+  uint32_t mRefreshRate;                       ///< Determines how often the task is processed.
 
   uint32_t mRefreshOnceCounter;
 
@@ -367,13 +377,15 @@ private:
 
   Dali::RenderTask::ScreenToFrameBufferFunction mScreenToFrameBufferFunction; ///< Used to convert screen to frame-buffer coordinates
 
+  uint32_t mRenderPass{0u};
+
   bool mExclusive : 1;    ///< True if the render-task has exclusive access to the source Nodes.
   bool mInputEnabled : 1; ///< True if the render-task should be considered for input handling.
   bool mClearEnabled : 1; ///< True if the render-task should be clear the color buffer.
   bool mCullMode : 1;     ///< True if the render-task's actors should be culled
   bool mRequiresSync : 1; ///< True if the GL sync is required to track the render of.
 
-  //Signals
+  // Signals
   Dali::RenderTask::RenderTaskSignalType mSignalFinished; ///< Signal emmited when the render task has been processed.
 };
 
index 74a8ab9..1420375 100644 (file)
@@ -46,6 +46,8 @@ Dali::Scripting::StringEnum ShaderHintsTable[] =
 
 const uint32_t ShaderHintsTableSize = static_cast<uint32_t>(sizeof(ShaderHintsTable) / sizeof(ShaderHintsTable[0]));
 
+static constexpr uint32_t DEFAULT_RENDER_PASS = 0u;
+
 BaseHandle Create()
 {
   return Dali::BaseHandle();
@@ -86,6 +88,36 @@ Property::Value HintString(const Dali::Shader::Hint::Value& hints)
   return Property::Value(s);
 }
 
+void GetShaderData(const Property::Map& shaderMap, std::string& vertexShader, std::string& fragmentShader, uint32_t& renderPass, Dali::Shader::Hint::Value& hints)
+{
+  hints      = Dali::Shader::Hint::NONE;
+  renderPass = 0u;
+
+  if(Property::Value* value = shaderMap.Find("vertex"))
+  {
+    vertexShader = value->Get<std::string>();
+  }
+
+  if(Property::Value* value = shaderMap.Find("fragment"))
+  {
+    fragmentShader = value->Get<std::string>();
+  }
+
+  if(Property::Value* value = shaderMap.Find("renderPass"))
+  {
+    renderPass = static_cast<uint32_t>(value->Get<int32_t>());
+  }
+
+  if(Property::Value* value = shaderMap.Find("hints"))
+  {
+    static_cast<void>( // ignore return
+      Scripting::GetEnumeration<Dali::Shader::Hint::Value>(value->Get<std::string>().c_str(),
+                                                           ShaderHintsTable,
+                                                           ShaderHintsTableSize,
+                                                           hints));
+  }
+}
+
 } // unnamed namespace
 
 ShaderPtr Shader::New(std::string_view          vertexShader,
@@ -93,7 +125,7 @@ ShaderPtr Shader::New(std::string_view          vertexShader,
                       Dali::Shader::Hint::Value hints)
 {
   // create scene object first so it's guaranteed to exist for the event side
-  auto                             sceneObject = new SceneGraph::Shader(hints);
+  auto                             sceneObject = new SceneGraph::Shader();
   OwnerPointer<SceneGraph::Shader> transferOwnership(sceneObject);
   // pass the pointer to base for message passing
   ShaderPtr shader(new Shader(sceneObject));
@@ -103,7 +135,25 @@ ShaderPtr Shader::New(std::string_view          vertexShader,
   AddShaderMessage(updateManager, transferOwnership);
 
   services.RegisterObject(shader.Get());
-  shader->SetShader(vertexShader, fragmentShader, hints);
+  shader->UpdateShaderData(vertexShader, fragmentShader, DEFAULT_RENDER_PASS, hints);
+
+  return shader;
+}
+
+ShaderPtr Shader::New(Dali::Property::Value shaderMap)
+{
+  // create scene object first so it's guaranteed to exist for the event side
+  auto                             sceneObject = new SceneGraph::Shader();
+  OwnerPointer<SceneGraph::Shader> transferOwnership(sceneObject);
+  // pass the pointer to base for message passing
+  ShaderPtr shader(new Shader(sceneObject));
+  // transfer scene object ownership to update manager
+  auto&&                     services      = shader->GetEventThreadServices();
+  SceneGraph::UpdateManager& updateManager = services.GetUpdateManager();
+  AddShaderMessage(updateManager, transferOwnership);
+
+  services.RegisterObject(shader.Get());
+  shader->SetShaderProperty(shaderMap);
 
   return shader;
 }
@@ -119,41 +169,7 @@ void Shader::SetDefaultProperty(Property::Index index, const Property::Value& pr
   {
     case Dali::Shader::Property::PROGRAM:
     {
-      if(propertyValue.GetType() == Property::MAP)
-      {
-        const Dali::Property::Map* map = propertyValue.GetMap();
-        if(map)
-        {
-          std::string               vertex;
-          std::string               fragment;
-          Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
-
-          if(Property::Value* value = map->Find("vertex"))
-          {
-            vertex = value->Get<std::string>();
-          }
-
-          if(Property::Value* value = map->Find("fragment"))
-          {
-            fragment = value->Get<std::string>();
-          }
-
-          if(Property::Value* value = map->Find("hints"))
-          {
-            static_cast<void>( // ignore return
-              Scripting::GetEnumeration<Dali::Shader::Hint::Value>(value->Get<std::string>().c_str(),
-                                                                   ShaderHintsTable,
-                                                                   ShaderHintsTableSize,
-                                                                   hints));
-          }
-
-          SetShader(vertex, fragment, hints);
-        }
-      }
-      else
-      {
-        DALI_LOG_WARNING("Shader program property should be a map\n");
-      }
+      SetShaderProperty(propertyValue);
       break;
     }
   }
@@ -167,14 +183,32 @@ Property::Value Shader::GetDefaultProperty(Property::Index index) const
   {
     case Dali::Shader::Property::PROGRAM:
     {
-      Dali::Property::Map map;
-      if(mShaderData)
+      if(mShaderDataList.size() == 1u)
       {
-        map["vertex"]   = Property::Value(mShaderData->GetVertexShader());
-        map["fragment"] = Property::Value(mShaderData->GetFragmentShader());
-        map["hints"]    = HintString(mShaderData->GetHints());
+        Dali::Property::Map map;
+        map["vertex"]     = Property::Value(mShaderDataList.front()->GetVertexShader());
+        map["fragment"]   = Property::Value(mShaderDataList.front()->GetFragmentShader());
+        map["renderPass"] = Property::Value(static_cast<int32_t>(mShaderDataList.front()->GetRenderPass()));
+        map["hints"]      = HintString(mShaderDataList.front()->GetHints());
+        value             = map;
+      }
+      else
+      {
+        Dali::Property::Array array;
+        for(auto&& shaderData : mShaderDataList)
+        {
+          if(shaderData)
+          {
+            Dali::Property::Map map;
+            map["vertex"]     = Property::Value(shaderData->GetVertexShader());
+            map["fragment"]   = Property::Value(shaderData->GetFragmentShader());
+            map["renderPass"] = Property::Value(static_cast<int32_t>(shaderData->GetRenderPass()));
+            map["hints"]      = HintString(shaderData->GetHints());
+            array.PushBack(map);
+          }
+        }
+        value = array;
       }
-      value = map;
       break;
     }
   }
@@ -188,24 +222,78 @@ Property::Value Shader::GetDefaultPropertyCurrentValue(Property::Index index) co
 }
 
 Shader::Shader(const SceneGraph::Shader* sceneObject)
-: Object(sceneObject),
-  mShaderData(nullptr)
+: Object(sceneObject)
 {
 }
 
-void Shader::SetShader(std::string_view          vertexSource,
-                       std::string_view          fragmentSource,
-                       Dali::Shader::Hint::Value hints)
+void Shader::UpdateShaderData(std::string_view          vertexSource,
+                              std::string_view          fragmentSource,
+                              uint32_t                  renderPass,
+                              Dali::Shader::Hint::Value hints)
 {
   // Try to load a pre-compiled shader binary for the source pair:
-  ThreadLocalStorage& tls           = ThreadLocalStorage::Get();
-  ShaderFactory&      shaderFactory = tls.GetShaderFactory();
-  size_t              shaderHash;
-  mShaderData = shaderFactory.Load(vertexSource, fragmentSource, hints, shaderHash);
+  ThreadLocalStorage&     tls           = ThreadLocalStorage::Get();
+  ShaderFactory&          shaderFactory = tls.GetShaderFactory();
+  size_t                  shaderHash;
+  Internal::ShaderDataPtr shaderData = shaderFactory.Load(vertexSource, fragmentSource, hints, renderPass, shaderHash);
+
+  std::vector<Internal::ShaderDataPtr>::iterator shaderDataIterator = std::find_if(mShaderDataList.begin(), mShaderDataList.end(), [&shaderData](const Internal::ShaderDataPtr& shaderDataItem)
+                                                                                   { return shaderDataItem->GetRenderPass() == shaderData->GetRenderPass(); });
+  if(shaderDataIterator != mShaderDataList.end())
+  {
+    *shaderDataIterator = shaderData;
+  }
+  else
+  {
+    mShaderDataList.push_back(shaderData);
+  }
 
   // Add shader data to scene-object
+  SceneGraph::UpdateShaderDataMessage(GetEventThreadServices(), GetShaderSceneObject(), shaderData);
+}
 
-  SceneGraph::SetShaderDataMessage(GetEventThreadServices(), GetShaderSceneObject(), mShaderData);
+void Shader::SetShaderProperty(const Dali::Property::Value& shaderMap)
+{
+  if(shaderMap.GetType() == Property::MAP)
+  {
+    const Dali::Property::Map* map = shaderMap.GetMap();
+    if(map)
+    {
+      std::string               vertex;
+      std::string               fragment;
+      uint32_t                  renderPass{0u};
+      Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
+      GetShaderData(*map, vertex, fragment, renderPass, hints);
+
+      UpdateShaderData(vertex, fragment, renderPass, hints);
+    }
+  }
+  else if(shaderMap.GetType() == Property::ARRAY)
+  {
+    const Dali::Property::Array* array = shaderMap.GetArray();
+    if(array)
+    {
+      uint32_t arraySize = array->Count();
+      for(uint32_t i = 0; i < arraySize; ++i)
+      {
+        const Dali::Property::Map* map = array->GetElementAt(i).GetMap();
+        if(map)
+        {
+          std::string               vertex;
+          std::string               fragment;
+          uint32_t                  renderPass{0u};
+          Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
+          GetShaderData(*map, vertex, fragment, renderPass, hints);
+
+          UpdateShaderData(vertex, fragment, renderPass, hints);
+        }
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("Shader program property should be a map or array of map.\n");
+  }
 }
 
 Shader::~Shader()
index 64008c5..76b4283 100644 (file)
@@ -53,6 +53,11 @@ public:
                        Dali::Shader::Hint::Value hints);
 
   /**
+   * @copydoc Dali::Shader::New()
+   */
+  static ShaderPtr New(Dali::Property::Value shaderMap);
+
+  /**
    * Retrieve the scene-graph shader added by this object.
    * @return A pointer to the shader.
    */
@@ -83,9 +88,22 @@ private: // implementation
   Shader(const SceneGraph::Shader* sceneObject);
 
   /**
-   * Second stage initialization
+   * @brief Update Shader Data
+   * If a ShaderData of the same renderPass is already exist, it is replaced,
+   * if not, new ShaderData is added.
+   * @param[in] vertexShader Vertex shader code for the effect.
+   * @param[in] fragmentShader Fragment Shader code for the effect.
+   * @param[in] renderPass render pass of shader data
+   * @param[in] hints Hints to define the geometry of the rendered object
+   */
+  void UpdateShaderData(std::string_view vertexShader, std::string_view fragmentShader, uint32_t renderPass, Dali::Shader::Hint::Value hints);
+
+  /**
+   * @brief Sets shader data from shaderMap.
+   * The shaderMap should be Property::Map or Property::Array.
+   * @param[in] shaderMap shader property map.
    */
-  void SetShader(std::string_view vertexShader, std::string_view fragmentShader, Dali::Shader::Hint::Value hints);
+  void SetShaderProperty(const Dali::Property::Value& shaderMap);
 
 protected:
   /**
@@ -94,12 +112,12 @@ protected:
   ~Shader() override;
 
 private: // unimplemented methods
-  Shader()              = delete;
-  Shader(const Shader&) = delete;
+  Shader()                         = delete;
+  Shader(const Shader&)            = delete;
   Shader& operator=(const Shader&) = delete;
 
 private:
-  Internal::ShaderDataPtr mShaderData;
+  std::vector<Internal::ShaderDataPtr> mShaderDataList;
 
 public:
   /**
index 52e7e68..c27f7f6 100644 (file)
@@ -132,13 +132,14 @@ public:
 public:                                  // Data
   Render::RenderTracker* mRenderTracker; ///< Pointer to an optional tracker object (not owned)
 
-  Viewport mViewport;              ///< Optional viewport
-  Vector4  mClearColor;            ///< Optional color to clear with
-  bool     mIsViewportSet : 1;     ///< Flag to determine whether the viewport is set
-  bool     mIsClearColorSet : 1;   ///< Flag to determine whether the clearColor is set
-  bool     mIgnoreRenderToFbo : 1; ///< Whether to ignore the render to FBO option (used to measure the performance above 60 fps)
+  Viewport mViewport;                    ///< Optional viewport
+  Vector4  mClearColor;                  ///< Optional color to clear with
+  bool     mIsViewportSet : 1;           ///< Flag to determine whether the viewport is set
+  bool     mIsClearColorSet : 1;         ///< Flag to determine whether the clearColor is set
+  bool     mIgnoreRenderToFbo : 1;       ///< Whether to ignore the render to FBO option (used to measure the performance above 60 fps)
 
   Render::FrameBuffer* mFrameBuffer;
+  uint32_t             mRenderPass{0u};
 
 private:                                             // Data
   Camera*                       mCamera;             ///< camera that is used
index d4d327c..032a6eb 100644 (file)
@@ -518,7 +518,12 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
   }
 
   // Create Program
-  ShaderDataPtr shaderData = mRenderDataProvider->GetShader().GetShaderData();
+  ShaderDataPtr shaderData = mRenderDataProvider->GetShader().GetShaderData(instruction.mRenderPass);
+  if(!shaderData)
+  {
+    DALI_LOG_ERROR("Failed to get shader data.\n");
+    return false;
+  }
 
   Program* program = Program::New(*mProgramCache,
                                   shaderData,
index 3b26fd5..6fedd4d 100644 (file)
@@ -31,25 +31,57 @@ namespace Internal
 {
 namespace SceneGraph
 {
-Shader::Shader(Dali::Shader::Hint::Value& hints)
-: mHints(hints)
+
+namespace
 {
+static constexpr uint32_t DEFAULT_RENDER_PASS = 0u;
 }
 
 Shader::~Shader()
 {
 }
 
-void Shader::SetShaderData(ShaderDataPtr shaderData)
+void Shader::UpdateShaderData(ShaderDataPtr shaderData)
 {
   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d\n", shaderData->GetHashValue());
-
-  mShaderData = shaderData;
+  std::vector<Internal::ShaderDataPtr>::iterator shaderDataIterator = std::find_if(mShaderDataList.begin(), mShaderDataList.end(), [&shaderData](const Internal::ShaderDataPtr& shaderDataItem)
+                                                                                   { return shaderDataItem->GetRenderPass() == shaderData->GetRenderPass(); });
+  if(shaderDataIterator != mShaderDataList.end())
+  {
+    *shaderDataIterator = shaderData;
+  }
+  else
+  {
+    mShaderDataList.push_back(shaderData);
+  }
 }
 
-ShaderDataPtr Shader::GetShaderData() const
+ShaderDataPtr Shader::GetShaderData(uint32_t renderPass) const
 {
-  return mShaderData;
+  if(mShaderDataList.empty())
+  {
+    return nullptr;
+  }
+
+  Internal::ShaderDataPtr returnShaderData = nullptr;
+  for(auto && shaderData : mShaderDataList)
+  {
+    if(shaderData->GetRenderPass() == renderPass)
+    {
+      return shaderData;
+    }
+    if(shaderData->GetRenderPass() == DEFAULT_RENDER_PASS)
+    {
+      returnShaderData = shaderData;
+    }
+  }
+
+  if(returnShaderData)
+  {
+    return returnShaderData;
+  }
+
+  return mShaderDataList.front();
 }
 
 } // namespace SceneGraph
index ff768e5..fbd3ea2 100644 (file)
@@ -50,11 +50,7 @@ class SceneController;
 class Shader : public PropertyOwner
 {
 public:
-  /**
-   * Constructor
-   * @param hints Shader hints
-   */
-  explicit Shader(Dali::Shader::Hint::Value& hints);
+  Shader() = default;
 
   /**
    * Virtual destructor
@@ -62,38 +58,24 @@ public:
   ~Shader() override;
 
   /**
-   * Query whether a shader hint is set.
-   *
-   * @warning This method is called from Update Algorithms.
-   *
-   * @pre The shader has been initialized.
-   * @param[in] hint The hint to check.
-   * @return True if the given hint is set.
-   */
-  [[nodiscard]] bool HintEnabled(Dali::Shader::Hint::Value hint) const
-  {
-    return mHints & hint;
-  }
-
-  /**
    * @brief Set the shader data for this shader.
    * @param[in] shaderData The program's vertex/fragment source and optionally pre-compiled shader binary.
    */
-  void SetShaderData(ShaderDataPtr shaderData);
+  void UpdateShaderData(ShaderDataPtr shaderData);
 
   /**
    * Get the shader data for this shader.
    * @return The shader data.
    */
-  [[nodiscard]] ShaderDataPtr GetShaderData() const;
+  [[nodiscard]] ShaderDataPtr GetShaderData(uint32_t renderPass) const;
 
 private: // Data
   Dali::Shader::Hint::Value mHints;
 
-  ShaderDataPtr mShaderData;
+  std::vector<ShaderDataPtr> mShaderDataList;
 };
 
-inline void SetShaderDataMessage(EventThreadServices& eventThreadServices, const Shader& shader, ShaderDataPtr shaderData)
+inline void UpdateShaderDataMessage(EventThreadServices& eventThreadServices, const Shader& shader, ShaderDataPtr shaderData)
 {
   using LocalType = MessageValue1<Shader, ShaderDataPtr>;
 
@@ -101,7 +83,7 @@ inline void SetShaderDataMessage(EventThreadServices& eventThreadServices, const
   uint32_t* 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(&shader, &Shader::SetShaderData, shaderData);
+  new(slot) LocalType(&shader, &Shader::UpdateShaderData, shaderData);
 }
 
 } // namespace SceneGraph
index e5f55f6..bd0b35c 100644 (file)
@@ -178,6 +178,7 @@ inline bool SetNodeUpdateArea(Node* node, bool isLayer3d, Matrix& nodeWorldMatri
 /**
  * Add a renderer to the list
  * @param updateBufferIndex to read the model matrix from
+ * @param renderPass render pass for this render instruction
  * @param renderList to add the item to
  * @param renderable Node-Renderer pair
  * @param viewMatrix used to calculate modelview matrix for the item
@@ -188,6 +189,7 @@ inline bool SetNodeUpdateArea(Node* node, bool isLayer3d, Matrix& nodeWorldMatri
  * @param cull Whether frustum culling is enabled or not
  */
 inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
+                                    uint32_t                  renderPass,
                                     RenderList&               renderList,
                                     Renderable&               renderable,
                                     const Matrix&             viewMatrix,
@@ -210,7 +212,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
   // Don't cull items which have render callback
   bool hasRenderCallback = (renderable.mRenderer && renderable.mRenderer->GetRenderCallback());
 
-  if(cull && renderable.mRenderer && (hasRenderCallback || (!renderable.mRenderer->GetShader().HintEnabled(Dali::Shader::Hint::MODIFIES_GEOMETRY) && node->GetClippingMode() == ClippingMode::DISABLED)))
+  if(cull && renderable.mRenderer && (hasRenderCallback || (renderable.mRenderer->GetShader().GetShaderData(renderPass) && !renderable.mRenderer->GetShader().GetShaderData(renderPass)->HintEnabled(Dali::Shader::Hint::MODIFIES_GEOMETRY) && node->GetClippingMode() == ClippingMode::DISABLED)))
   {
     const Vector4& boundingSphere = node->GetBoundingSphere();
     inside                        = (boundingSphere.w > Math::MACHINE_EPSILON_1000) &&
@@ -252,7 +254,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
     bool isOpaque = true;
     if(!hasRenderCallback)
     {
-      Renderer::OpacityType opacityType = renderable.mRenderer ? renderable.mRenderer->GetOpacityType(updateBufferIndex, *node) : Renderer::OPAQUE;
+      Renderer::OpacityType opacityType = renderable.mRenderer ? renderable.mRenderer->GetOpacityType(updateBufferIndex, renderPass, *node) : Renderer::OPAQUE;
 
       // We can skip render when node is not clipping and transparent
       skipRender = (opacityType == Renderer::TRANSPARENT && node->GetClippingMode() == ClippingMode::DISABLED);
@@ -363,6 +365,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 /**
  * Add all renderers to the list
  * @param updateBufferIndex to read the model matrix from
+ * @param renderPass render pass for this render instruction
  * @param renderList to add the items to
  * @param renderers to render
  * NodeRendererContainer Node-Renderer pairs
@@ -372,6 +375,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
  * @param cull Whether frustum culling is enabled or not
  */
 inline void AddRenderersToRenderList(BufferIndex               updateBufferIndex,
+                                     uint32_t                  renderPass,
                                      RenderList&               renderList,
                                      RenderableContainer&      renderers,
                                      const Matrix&             viewMatrix,
@@ -386,6 +390,7 @@ inline void AddRenderersToRenderList(BufferIndex               updateBufferIndex
   for(auto&& renderer : renderers)
   {
     AddRendererToRenderList(updateBufferIndex,
+                            renderPass,
                             renderList,
                             renderer,
                             viewMatrix,
@@ -590,6 +595,7 @@ void RenderInstructionProcessor::Prepare(BufferIndex                 updateBuffe
       {
         renderList->SetHasColorRenderItems(true);
         AddRenderersToRenderList(updateBufferIndex,
+                                 instruction.mRenderPass,
                                  *renderList,
                                  renderables,
                                  viewMatrix,
@@ -614,6 +620,7 @@ void RenderInstructionProcessor::Prepare(BufferIndex                 updateBuffe
       {
         renderList->SetHasColorRenderItems(false);
         AddRenderersToRenderList(updateBufferIndex,
+                                 instruction.mRenderPass,
                                  *renderList,
                                  renderables,
                                  viewMatrix,
index 90dca93..ea5793e 100644 (file)
@@ -400,6 +400,7 @@ RenderInstruction& RenderTask::PrepareRenderInstruction(BufferIndex updateBuffer
     mRenderInstruction[updateBufferIndex].mRenderTracker = nullptr;
   }
 
+  mRenderInstruction[updateBufferIndex].mRenderPass = mRenderPass;
   return mRenderInstruction[updateBufferIndex];
 }
 
@@ -478,6 +479,11 @@ void RenderTask::SetSyncRequired(bool requiresSync)
   mRequiresSync = requiresSync;
 }
 
+void RenderTask::SetRenderPass(uint32_t renderPass)
+{
+  mRenderPass = renderPass;
+}
+
 void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
 {
   // check if we've gone from inactive to active
index 0d5142c..a2336f3 100644 (file)
@@ -354,6 +354,15 @@ public:
     return mRenderInstruction[updateBufferIndex];
   }
 
+  /**
+   * Sets Render Pass key for this RenderTask.
+   * Shader code that matches this render pass is used for rendering.
+   * If no matching shader is found, the code with a render pass of 0 is used.
+   * In other cases, operation is not guaranteed.
+   * @param[in] renderPass RenderPass value for this render task.
+   */
+  void SetRenderPass(uint32_t renderPass);
+
 private: // from PropertyOwner::Observer
   /**
    * @copydoc PropertyOwner::Observer::PropertyOwnerConnected( PropertyOwner& owner )
@@ -379,7 +388,7 @@ private:
   RenderTask();
 
   // Undefined
-  RenderTask(const RenderTask&) = delete;
+  RenderTask(const RenderTask&)            = delete;
   RenderTask& operator=(const RenderTask&) = delete;
 
 public:                                          // Animatable Properties
@@ -398,11 +407,13 @@ private:
 
   RenderInstruction mRenderInstruction[2]; ///< Owned double buffered render instruction. (Double buffered because this owns render commands for the currently drawn frame)
 
-  uint32_t mRefreshRate;         ///< REFRESH_ONCE, REFRESH_ALWAYS or render every N frames
-  uint32_t mFrameCounter;        ///< counter for rendering every N frames
-  uint32_t mRenderedOnceCounter; ///< Incremented whenever state changes to RENDERED_ONCE_AND_NOTIFIED
+  uint32_t mRefreshRate;                   ///< REFRESH_ONCE, REFRESH_ALWAYS or render every N frames
+  uint32_t mFrameCounter;                  ///< counter for rendering every N frames
+  uint32_t mRenderedOnceCounter;           ///< Incremented whenever state changes to RENDERED_ONCE_AND_NOTIFIED
+
+  State mState;                            ///< Render state.
 
-  State mState; ///< Render state.
+  uint32_t mRenderPass{0u};
 
   bool mRequiresSync : 1;    ///< Whether sync is needed to track the render
   bool mActive : 1;          ///< True when the task is active, i.e. has valid source and camera
@@ -565,6 +576,17 @@ inline void BakeViewportSizeMessage(EventThreadServices& eventThreadServices, co
   new(slot) LocalType(&task, &RenderTask::BakeViewportSize, value);
 }
 
+inline void SetRenderPassMessage(EventThreadServices& eventThreadServices, const RenderTask& task, uint32_t renderPass)
+{
+  using LocalType = MessageValue1<RenderTask, uint32_t>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* 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(&task, &RenderTask::SetRenderPass, renderPass);
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index 89eb545..4d73b0d 100644 (file)
@@ -589,7 +589,7 @@ Render::Renderer& Renderer::GetRenderer()
   return *mRenderer;
 }
 
-Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, const Node& node) const
+Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, uint32_t renderPass, const Node& node) const
 {
   Renderer::OpacityType opacityType = Renderer::OPAQUE;
 
@@ -626,10 +626,13 @@ Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, co
         break;
       }
 
-      bool shaderRequiresBlending(mShader->HintEnabled(Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT));
-      if(shaderRequiresBlending || (mTextureSet && mTextureSet->HasAlpha()))
+      if(mShader->GetShaderData(renderPass))
       {
-        opacityType = Renderer::TRANSLUCENT;
+        bool shaderRequiresBlending(mShader->GetShaderData(renderPass)->HintEnabled(Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT));
+        if(shaderRequiresBlending || (mTextureSet && mTextureSet->HasAlpha()))
+        {
+          opacityType = Renderer::TRANSLUCENT;
+        }
       }
 
       // renderer should determine opacity using the actor color
index 1e672a0..0bef132 100644 (file)
@@ -352,9 +352,10 @@ public:
   /**
    * Query whether the renderer is fully opaque, fully transparent or transparent.
    * @param[in] updateBufferIndex The current update buffer index.
+   * @param[in] renderPass render pass for this render instruction
    * @return OPAQUE if fully opaque, TRANSPARENT if fully transparent and TRANSLUCENT if in between
    */
-  OpacityType GetOpacityType(BufferIndex updateBufferIndex, const Node& node) const;
+  OpacityType GetOpacityType(BufferIndex updateBufferIndex, uint32_t renderPass, const Node& node) const;
 
   /**
    * Connect the object to the scene graph
index e59bd82..4fdc74c 100644 (file)
@@ -273,6 +273,16 @@ bool RenderTask::ViewportToLocal(Actor actor, float viewportX, float viewportY,
   }
 }
 
+void RenderTask::SetRenderPass(uint32_t renderPass)
+{
+  GetImplementation(*this).SetRenderPass(renderPass);
+}
+
+uint32_t RenderTask::GetRenderPass() const
+{
+  return GetImplementation(*this).GetRenderPass();
+}
+
 RenderTask::RenderTask(Internal::RenderTask* internal)
 : Handle(internal)
 {
index 0832c4b..52c6764 100644 (file)
@@ -535,6 +535,21 @@ public:
    */
   bool ViewportToLocal(Actor actor, float viewportX, float viewportY, float& localX, float& localY) const;
 
+  /**
+   * Sets Render Pass key for this RenderTask.
+   * Shader code that matches this render pass is used for rendering.
+   * If no matching shader is found, the code with a render pass of 0 is used.
+   * In other cases, operation is not guaranteed.
+   * @param[in] renderPass RenderPass value for this render task.
+   */
+  void SetRenderPass(uint32_t renderPass);
+
+  /**
+   * Gets Render Pass key for this RenderTask.
+   * @return RenderPass value for this render task.
+   */
+  uint32_t GetRenderPass() const;
+
 public: // Signals
   /**
    * @brief If the refresh rate is REFRESH_ONCE, connect to this signal to be notified when a RenderTask has finished.
index 7456d9e..02b95ff 100644 (file)
@@ -27,8 +27,14 @@ Shader Shader::New(std::string_view vertexShader,
                    std::string_view fragmentShader,
                    Hint::Value      hints)
 {
-  Internal::ShaderPtr renderer = Internal::Shader::New(vertexShader, fragmentShader, hints);
-  return Shader(renderer.Get());
+  Internal::ShaderPtr shader = Internal::Shader::New(vertexShader, fragmentShader, hints);
+  return Shader(shader.Get());
+}
+
+Shader Shader::New(Dali::Property::Value shaderMap)
+{
+  Internal::ShaderPtr shader = Internal::Shader::New(shaderMap);
+  return Shader(shader.Get());
 }
 
 Shader::Shader() = default;
index 19e138d..c60b92f 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali/public-api/object/handle.h>                // Dali::Handle
 #include <dali/public-api/object/property-index-ranges.h> // DEFAULT_DERIVED_HANDLE_PROPERTY_START_INDEX
+#include <dali/public-api/object/property-value.h>
 
 /**
  * @brief DALI_COMPOSE_SHADER macro provides a convenient way to write shader source code.
@@ -106,12 +107,13 @@ public:
     enum
     {
       /**
-       * @brief Name: "program", Type: MAP.
+       * @brief Name: "program", Type: MAP or ARRAY.
        * @note The default value is empty.
-       * @note Format: {"vertex":"","fragment":"",hints:""}
+       * @note It is Property::Map or Property::Array of the map.
+       * @note Format: {"renderPass":"", "vertex":"", "fragment":"", "hints":""}
        * @SINCE_1_1.43
        */
-      PROGRAM = DEFAULT_OBJECT_PROPERTY_START_INDEX
+      PROGRAM = DEFAULT_OBJECT_PROPERTY_START_INDEX,
     };
   };
 
@@ -129,6 +131,17 @@ public:
                     Hint::Value      hints = Hint::NONE);
 
   /**
+   * @brief Creates Shader.
+   *
+   * @SINCE_2_2.31
+   * @param[in] shaderMap Property::Map of shader data or Property::Array of Property::Map.
+   * Property::Map format is {"renderPass":"", "vertex":"", "fragment":"", "hints":""}
+   * shaderMap can be Property::Array of Property::Map for multi pass shading.
+   * @return A handle to a shader effect
+   */
+  static Shader New(Dali::Property::Value shaderMap);
+
+  /**
    * @brief Default constructor, creates an empty handle.
    *
    * @SINCE_1_1.43