* 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.
*
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);
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;
+}
"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;
{
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;
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;
+}
* @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)
{
}
* @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
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
}
}
-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());
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();
*
* @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.
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);
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;
/**
*/
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.
*/
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.
~RenderTask() override;
private: // not copyable
- RenderTask() = delete;
- RenderTask(const RenderTask&) = delete;
+ RenderTask() = delete;
+ RenderTask(const RenderTask&) = delete;
RenderTask& operator=(const RenderTask&) = delete;
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;
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.
};
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();
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,
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));
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;
}
{
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;
}
}
{
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;
}
}
}
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()
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.
*/
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:
/**
~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:
/**
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
}
// 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,
{
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
class Shader : public PropertyOwner
{
public:
- /**
- * Constructor
- * @param hints Shader hints
- */
- explicit Shader(Dali::Shader::Hint::Value& hints);
+ Shader() = default;
/**
* Virtual destructor
~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>;
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
/**
* 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
* @param cull Whether frustum culling is enabled or not
*/
inline void AddRendererToRenderList(BufferIndex updateBufferIndex,
+ uint32_t renderPass,
RenderList& renderList,
Renderable& renderable,
const Matrix& viewMatrix,
// 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) &&
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);
/**
* 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
* @param cull Whether frustum culling is enabled or not
*/
inline void AddRenderersToRenderList(BufferIndex updateBufferIndex,
+ uint32_t renderPass,
RenderList& renderList,
RenderableContainer& renderers,
const Matrix& viewMatrix,
for(auto&& renderer : renderers)
{
AddRendererToRenderList(updateBufferIndex,
+ renderPass,
renderList,
renderer,
viewMatrix,
{
renderList->SetHasColorRenderItems(true);
AddRenderersToRenderList(updateBufferIndex,
+ instruction.mRenderPass,
*renderList,
renderables,
viewMatrix,
{
renderList->SetHasColorRenderItems(false);
AddRenderersToRenderList(updateBufferIndex,
+ instruction.mRenderPass,
*renderList,
renderables,
viewMatrix,
mRenderInstruction[updateBufferIndex].mRenderTracker = nullptr;
}
+ mRenderInstruction[updateBufferIndex].mRenderPass = mRenderPass;
return mRenderInstruction[updateBufferIndex];
}
mRequiresSync = requiresSync;
}
+void RenderTask::SetRenderPass(uint32_t renderPass)
+{
+ mRenderPass = renderPass;
+}
+
void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
{
// check if we've gone from inactive to active
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 )
RenderTask();
// Undefined
- RenderTask(const RenderTask&) = delete;
+ RenderTask(const RenderTask&) = delete;
RenderTask& operator=(const RenderTask&) = delete;
public: // Animatable Properties
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
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
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;
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
/**
* 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
}
}
+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)
{
*/
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.
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;
// 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.
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,
};
};
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