From: Agnelo Vaz Date: Tue, 26 Sep 2017 19:19:51 +0000 (+0100) Subject: ImageVisual Release policy X-Git-Tag: dali_1.2.62~4 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=651041b7a488a722887c0134174f3349d4775237 ImageVisual Release policy ImageVisual can be created with a PropertyMap that inserts a release policy. Depending on release policy the image lifetime in the texture cache will change. Can be used for images that are often put on and taken off stage to reduce re-loading time. Change-Id: If275630f236174ebbea3fde4cefae015b8db3a0f --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index c40af67..d0e1561 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -19,11 +19,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include "dummy-control.h" @@ -1064,6 +1064,9 @@ int UtcDaliImageVisualAlphaMask(void) DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION ); + dummyImpl.UnregisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1 ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + END_TEST; } @@ -1179,3 +1182,433 @@ int UtcDaliImageVisualAlphaMaskCrop(void) END_TEST; } + +int UtcDaliImageVisualReleasePolicy01(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy01 Detached Policy, disabling visual with this policy deletes texture" ); + + VisualFactory factory = VisualFactory::Get(); + + Property::Map propertyMap; + propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DETACHED ); + + Visual::Base imageVisual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK( imageVisual ); + + // Set up debug trace + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visual with control and ensure it has the only handle" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); + imageVisual.Reset(); + + actor.SetSize(200.f, 200.f); + + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + // Test renderer and texture created + tet_infoline( "Confirm texture created" ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + + tet_infoline( "Disable visual causing the texture to be deleted" ); + dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false ); + + application.SendNotification(); + application.Render(0); + // Test renderer and textures removed. + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy02(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy02 Destroyed Policy, Texture should be deleted when visual destroyed" ); + + VisualFactory factory = VisualFactory::Get(); + const std::string MASK_IMAGE = TEST_REMOTE_IMAGE_FILE_NAME; + + Property::Map propertyMap; + propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( Visual::Property::MIX_COLOR, Color::MAGENTA ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED ); + + Visual::Base imageVisual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK( imageVisual ); + + // Setup debug trace + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visual with control and ensure it has the only handle" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); + imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive. + + actor.SetSize(200.f, 200.f); + + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + // Test renderer and texture created + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + + + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + tet_infoline( "Destroy visual by UnRegistering visual with control, check renderer is destroyed" ); + dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + application.SendNotification(); + application.Render(); + + // Test texture removed after visual destroyed. + tet_infoline( "Ensure texture is deleted after visual destroyed" ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy03(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy03 Never Policy, texture should not be deleted after visual destroyed" ); + + VisualFactory factory = VisualFactory::Get(); + + Property::Map propertyMap; + propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER ); + + Visual::Base imageVisual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK( imageVisual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visual with control and ensure it has the only handle" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); + imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive. + + actor.SetSize(200.f, 200.f); + + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + // Test renderer and texture created + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + + tet_infoline( "Destroy visual by UnRegistering visual with control, check renderer is destroyed" ); + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + application.SendNotification(); + application.Render(); + + tet_infoline( "Ensure texture is not deleted as policy is set to NEVER" ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy04(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy04 Two visuals with different policies sharing a texture" ); + + VisualFactory factory = VisualFactory::Get(); + + tet_infoline( "Create first visual with Never release policy" ); + Property::Map propertyMapNeverReleasePolicy; + propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMapNeverReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER ); + Visual::Base imageVisualNever = factory.CreateVisual( propertyMapNeverReleasePolicy ); + + tet_infoline( "Create second visual with Destroyed release policy"); + Property::Map propertyMapDestroyedReleasePolicy; + propertyMapDestroyedReleasePolicy.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMapDestroyedReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED ); + Visual::Base imageVisualDestroyed = factory.CreateVisual( propertyMapDestroyedReleasePolicy ); + + // Set up trace debug + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visuals with control and ensure it has the only handles" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisualNever ); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, imageVisualDestroyed ); + imageVisualNever.Reset(); // reduce ref count so only the control keeps the visual alive. + imageVisualDestroyed.Reset(); // reduce ref count so only the control keeps the visual alive. + + actor.SetSize(200.f, 200.f); + + // Test initially zero renderers + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + tet_infoline( "Ensure a texture is created, shared amongst both visuals. Each visual has its own renderer" ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 2u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + + // Test renderer removed when visual destroyed + DALI_TEST_CHECK( actor.GetRendererCount() == 2u ); + dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL2 ); // TEST_VISUAL2 no longer requires the texture as release policy DESTROYED + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + application.SendNotification(); + application.Render(); + + // Test texture was not deleted as TEST_VISUAL release policy is NEVER so it is still required. + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + application.SendNotification(); + application.Render(); + + tet_infoline( "Ensure a texture is not deleted as second visual used the NEVER release policy" ); + // Test texture was not deleted as TEST_VISUAL release policy is NEVER so it is still required. + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy05(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy05 Testing settung by string currents correct enum" ); + + VisualFactory factory = VisualFactory::Get(); + + Property::Map propertyMapNeverReleasePolicy; + propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMapNeverReleasePolicy.Insert( "releasePolicy" , "never" ); + + Visual::Base imageVisualNever = factory.CreateVisual( propertyMapNeverReleasePolicy ); + + Property::Map resultMap; + imageVisualNever.CreatePropertyMap( resultMap ); + DALI_TEST_CHECK( ! resultMap.Empty() ); + + DALI_TEST_EQUALS( ( resultMap.Find( DevelImageVisual::Property::RELEASE_POLICY ) )->Get(), (int)DevelImageVisual::ReleasePolicy::NEVER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy06(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy06 Never Policy, texture should not be affected by Disabling and Enabling visual" ); + + VisualFactory factory = VisualFactory::Get(); + + Property::Map propertyMap; + propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER ); + + Visual::Base imageVisual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK( imageVisual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visual with control and ensure it has the only handle" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); + imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive. + + actor.SetSize(200.f, 200.f); + + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + // Test renderer and texture created + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + textureTrace.Reset(); + + tet_infoline( "Disable Visual and check texture not affected" ); + dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false ); + application.SendNotification(); + application.Render(0); + tet_infoline( "Check renderer is destroyed when visual off stage" ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + textureTrace.Reset(); + + tet_infoline( "Re-enable Visual and check texture not affected" ); + dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, true ); + application.SendNotification(); + application.Render(0); + tet_infoline( "Check texture not affected and renderer is destroyed when visual off stage" ); + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageVisualReleasePolicy07(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualReleasePolicy07 Two visuals with different policies sharing a texture DETACHED and DESTROYED" ); + + VisualFactory factory = VisualFactory::Get(); + + tet_infoline( "Create first visual with DESTROYED release policy" ); + Property::Map propertyMapNeverReleasePolicy; + propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMapNeverReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED ); + Visual::Base imageVisualDestroyed = factory.CreateVisual( propertyMapNeverReleasePolicy ); + + tet_infoline( "Create second visual with DETACHED release policy"); + Property::Map propertyMapDestroyedReleasePolicy; + propertyMapDestroyedReleasePolicy.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); + propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); + propertyMapDestroyedReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DETACHED ); + Visual::Base imageVisualDetached = factory.CreateVisual( propertyMapDestroyedReleasePolicy ); + + // Set up trace debug + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + tet_infoline( "Register visuals with control and ensure it has the only handles" ); + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisualDestroyed ); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, imageVisualDetached ); + imageVisualDestroyed.Reset(); // reduce ref count so only the control keeps the visual alive. + imageVisualDetached.Reset(); // reduce ref count so only the control keeps the visual alive. + + actor.SetSize(200.f, 200.f); + + // Test initially zero renderers + application.SendNotification(); + application.Render(0); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + // Wait for image to load + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + tet_infoline( "Ensure a texture is created, shared amongst both visuals. Each visual has its own renderer" ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 2u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION ); + + // Test renderer removed when visual destroyed + DALI_TEST_CHECK( actor.GetRendererCount() == 2u ); + dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL2, false ); // TEST_VISUAL2 no longer requires the texture as release policy DETACHED + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + application.SendNotification(); + application.Render(); + + // Test texture was not deleted as TEST_VISUAL release policy is DESTROYED and is still required. + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + application.SendNotification(); + application.Render(); + + tet_infoline( "Ensure a texture is not deleted as second visual used the DESTROYED release policy" ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + END_TEST; +} diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index ed9059d..f93beb1 100644 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -45,6 +45,9 @@ devel_api_src_files = \ devel_api_header_files = \ $(devel_api_src_dir)/direction-enums.h +devel_api_visuals_header_files = \ + $(devel_api_src_dir)/visuals/image-visual-properties-devel.h + devel_api_controls_header_files = \ $(devel_api_src_dir)/controls/control-depth-index-ranges.h \ $(devel_api_src_dir)/controls/control-devel.h \ diff --git a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h new file mode 100644 index 0000000..e812c5b --- /dev/null +++ b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h @@ -0,0 +1,94 @@ +#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H +#define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H + +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace DevelImageVisual +{ + + +/** + * @brief The policy determining when a image is deleted from the cache in relation to the ImageVisual lifetime. + * @note If the texture is being shared by another visual it persist if still required. + */ +namespace ReleasePolicy +{ + +/** + * @brief The available named elements that define the ReleasePolicy. + */ +enum Type +{ + DETACHED = 0, ///< Image deleted from cache when ImageVisual detached from stage. + DESTROYED, ///< Image deleted from cache when ImageVisual destroyed. + NEVER ///< Image is never deleted, will survive the lifetime of the application. +}; + +} // namespace ReleasePolicy; + +namespace Property +{ + +enum Type +{ + URL = Dali::Toolkit::ImageVisual::Property::URL, + FITTING_MODE = Dali::Toolkit::ImageVisual::Property::FITTING_MODE, + SAMPLING_MODE = Dali::Toolkit::ImageVisual::Property::SAMPLING_MODE, + DESIRED_WIDTH = Dali::Toolkit::ImageVisual::Property::DESIRED_WIDTH, + DESIRED_HEIGHT = Dali::Toolkit::ImageVisual::Property::DESIRED_HEIGHT, + SYNCHRONOUS_LOADING = Dali::Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, + BORDER_ONLY = Dali::Toolkit::ImageVisual::Property::BORDER_ONLY, + PIXEL_AREA = Dali::Toolkit::ImageVisual::Property::PIXEL_AREA, + WRAP_MODE_U = Dali::Toolkit::ImageVisual::Property::WRAP_MODE_U, + WRAP_MODE_V = Dali::Toolkit::ImageVisual::Property::WRAP_MODE_V, + BORDER = Dali::Toolkit::ImageVisual::Property::BORDER, + ATLASING = Dali::Toolkit::ImageVisual::Property::ATLASING, + ALPHA_MASK_URL = Dali::Toolkit::ImageVisual::Property::ALPHA_MASK_URL, + BATCH_SIZE = Dali::Toolkit::ImageVisual::Property::BATCH_SIZE, + CACHE_SIZE = Dali::Toolkit::ImageVisual::Property::CACHE_SIZE, + FRAME_DELAY = Dali::Toolkit::ImageVisual::Property::FRAME_DELAY, + MASK_CONTENT_SCALE = Dali::Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, + CROP_TO_MASK = Dali::Toolkit::ImageVisual::Property::CROP_TO_MASK, + + /** + * @brief The policy to determine when an image should no longer be cached. + * @details Name "releasePolicy", Type ReleasePolicy::Type (Property::INTEGER) or Property::STRING + * @note Default ReleasePolicy::DETACHED + * @see ReleasePolicy::Type + */ + RELEASE_POLICY = CROP_TO_MASK + 2, +}; + +} //namespace Property + +} // namespace DevelImageVisual + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index c83bd6e..4d30053 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -91,6 +91,13 @@ DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT ) DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT ) DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE ) +// release policies +DALI_ENUM_TO_STRING_TABLE_BEGIN( RELEASE_POLICY ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, DETACHED ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, DESTROYED ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, NEVER ) +DALI_ENUM_TO_STRING_TABLE_END( RELEASE_POLICY ) + const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D"; @@ -267,8 +274,9 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, mSamplingMode( samplingMode ), mWrapModeU( WrapMode::DEFAULT ), mWrapModeV( WrapMode::DEFAULT ), + mReleasePolicy( DevelImageVisual::ReleasePolicy::DETACHED ), mAttemptAtlasing( false ), - mLoadingStatus( false ) + mLoading( false ) { } @@ -285,22 +293,32 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image ) mSamplingMode( SamplingMode::DEFAULT ), mWrapModeU( WrapMode::DEFAULT ), mWrapModeV( WrapMode::DEFAULT ), + mReleasePolicy( DevelImageVisual::ReleasePolicy::DETACHED ), mAttemptAtlasing( false ), - mLoadingStatus( false ) + mLoading( false ) { } ImageVisual::~ImageVisual() { - if( mMaskingData && Stage::IsInstalled() ) + if( Stage::IsInstalled() ) { - // TextureManager could have been deleted before the actor that contains this - // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage - // is still valid before accessing texture manager. - if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID ) + if( mMaskingData ) + { + // TextureManager could have been deleted before the actor that contains this + // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage + // is still valid before accessing texture manager. + if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID ) + { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + textureManager.Remove( mMaskingData->mAlphaMaskId ); + } + } + + // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release + if( ( mTextureId != TextureManager::INVALID_TEXTURE_ID ) && ( mReleasePolicy != DevelImageVisual::ReleasePolicy::NEVER ) ) { - TextureManager& textureManager = mFactoryCache.GetTextureManager(); - textureManager.Remove( mMaskingData->mAlphaMaskId ); + RemoveTexture(); } } } @@ -349,22 +367,26 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap ) { DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second ); } - else if ( keyValue.first == IMAGE_ATLASING ) + else if( keyValue.first == IMAGE_ATLASING ) { DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second ); } - else if ( keyValue.first == ALPHA_MASK_URL ) + else if( keyValue.first == ALPHA_MASK_URL ) { DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second ); } - else if ( keyValue.first == MASK_CONTENT_SCALE_NAME ) + else if( keyValue.first == MASK_CONTENT_SCALE_NAME ) { DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second ); } - else if ( keyValue.first == CROP_TO_MASK_NAME ) + else if( keyValue.first == CROP_TO_MASK_NAME ) { DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second ); } + else if( keyValue.first == RELEASE_POLICY_NAME ) + { + DoSetProperty( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, keyValue.second ); + } } } } @@ -502,6 +524,14 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v } break; } + + case Toolkit::DevelImageVisual::Property::RELEASE_POLICY: + { + int releasePolicy; + Scripting::GetEnumerationProperty( value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy ); + mReleasePolicy = DevelImageVisual::ReleasePolicy::Type( releasePolicy ); + break; + } } } @@ -708,7 +738,7 @@ void ImageVisual::InitializeRenderer() TextureSet textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, IsSynchronousResourceLoading(), mTextureId, - atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, + atlasRect, attemptAtlasing, mLoading, mWrapModeU, mWrapModeV, this, this, mFactoryCache.GetAtlasManager()); if(attemptAtlasing) { @@ -735,7 +765,7 @@ void ImageVisual::InitializeRenderer() TextureSet textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, IsSynchronousResourceLoading(), mTextureId, - atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, mWrapModeV, this, + atlasRect, attemptAtlasing, mLoading, mWrapModeU, mWrapModeV, this, nullptr, nullptr); // no atlasing DALI_ASSERT_DEBUG(attemptAtlasing == false); CreateRenderer( textures ); @@ -767,12 +797,12 @@ void ImageVisual::DoSetOnStage( Actor& actor ) { InitializeRenderer(); } - else if ( mImage ) + else if( mImage ) { InitializeRenderer( mImage ); } - if ( !mImpl->mRenderer ) + if( !mImpl->mRenderer ) { return; } @@ -780,7 +810,7 @@ void ImageVisual::DoSetOnStage( Actor& actor ) mPlacementActor = actor; // Search the Actor tree to find if Layer UI behaviour set. Layer layer = actor.GetLayer(); - if ( layer && layer.GetBehavior() == Layer::LAYER_3D ) + if( layer && layer.GetBehavior() == Layer::LAYER_3D ) { // Layer 3D set, do not align pixels mImpl->mRenderer.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF ); @@ -791,7 +821,7 @@ void ImageVisual::DoSetOnStage( Actor& actor ) mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea ); } - if( mLoadingStatus == false ) + if( mLoading == false ) { actor.AddRenderer( mImpl->mRenderer ); mPlacementActor.Reset(); @@ -805,14 +835,19 @@ void ImageVisual::DoSetOffStage( Actor& actor ) { // Visual::Base::SetOffStage only calls DoSetOffStage if mRenderer exists (is on onstage) - //If we own the image then make sure we release it when we go off stage + // Image release is dependent on the ReleasePolicy, renderer is destroyed. actor.RemoveRenderer( mImpl->mRenderer); + if( mReleasePolicy == DevelImageVisual::ReleasePolicy::DETACHED ) + { + RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + } + if( mImageUrl.IsValid() ) { - RemoveTexture( mImageUrl.GetUrl() ); + // Legacy support for deprecated Dali::Image mImage.Reset(); } - mLoadingStatus = false; + mLoading = false; mImpl->mRenderer.Reset(); mPlacementActor.Reset(); } @@ -856,6 +891,9 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const map.Insert( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor ); map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask ); } + + map.Insert( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, mReleasePolicy ); + } void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const @@ -948,7 +986,7 @@ void ImageVisual::UploadCompleted() // reset the weak handle so that the renderer only get added to actor once mPlacementActor.Reset(); } - mLoadingStatus = false; + mLoading = false; } // From Texture Manager @@ -983,10 +1021,10 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur ResourceReady(); } } - mLoadingStatus = false; + mLoading = false; } -void ImageVisual::RemoveTexture(const std::string& url) +void ImageVisual::RemoveTexture() { if( mTextureId != TextureManager::INVALID_TEXTURE_ID ) { diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index d56ab14..0e4009b 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace Dali { @@ -64,6 +65,7 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr; * | pixelArea | VECTOR4 | * | wrapModeU | INTEGER OR STRING | * | wrapModeV | INTEGER OR STRING | + * | releasePolicy | INTEGER OR STRING | * * where pixelArea is a rectangular area. * In its Vector4 value, the first two elements indicate the top-left position of the area, @@ -95,6 +97,11 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr; * "DEFAULT" * * + * where releasePolicy should be one of the following policies for when to cache the image + * "DETACHED" // Release image from cache when visual detached from stage + * "DESTROYED" // Keep image in cache until the visual is destroyed + * "NEVER" // Keep image in cache until application ends. + * * If the Visual is in a LayerUI it will pixel align the image, using a Layer3D will disable pixel alignment. * Changing layer behaviour between LayerUI to Layer3D whilst the visual is already staged will not have an effect. */ @@ -304,9 +311,9 @@ private: void SetTextureRectUniform( const Vector4& textureRect ); /** - * Remove the texture if it is not used anymore. + * Remove texture with valid TextureId */ - void RemoveTexture(const std::string& url); + void RemoveTexture(); /** * Helper method to set individual values by index key. @@ -330,8 +337,9 @@ private: Dali::SamplingMode::Type mSamplingMode:4; Dali::WrapMode::Type mWrapModeU:3; Dali::WrapMode::Type mWrapModeV:3; + DevelImageVisual::ReleasePolicy::Type mReleasePolicy; bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture - bool mLoadingStatus; ///< True if the texture is being loaded asynchronously, or false when it has loaded. + bool mLoading; ///< True if the texture is still loading. }; diff --git a/dali-toolkit/internal/visuals/visual-string-constants.cpp b/dali-toolkit/internal/visuals/visual-string-constants.cpp index b3352d4..0670dd8 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.cpp +++ b/dali-toolkit/internal/visuals/visual-string-constants.cpp @@ -85,6 +85,7 @@ const char * const CACHE_SIZE_NAME("cacheSize"); const char * const FRAME_DELAY_NAME("frameDelay"); const char * const MASK_CONTENT_SCALE_NAME("maskContentScale"); const char * const CROP_TO_MASK_NAME("cropToMask"); +const char * const RELEASE_POLICY_NAME("releasePolicy"); // Text visual const char * const TEXT_PROPERTY( "text" ); diff --git a/dali-toolkit/internal/visuals/visual-string-constants.h b/dali-toolkit/internal/visuals/visual-string-constants.h index 4731f4a..9aa14a1 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.h +++ b/dali-toolkit/internal/visuals/visual-string-constants.h @@ -73,6 +73,7 @@ extern const char * const CACHE_SIZE_NAME; extern const char * const FRAME_DELAY_NAME; extern const char * const MASK_CONTENT_SCALE_NAME; extern const char * const CROP_TO_MASK_NAME; +extern const char * const RELEASE_POLICY_NAME; // Text visual extern const char * const TEXT_PROPERTY;