From: David Steele Date: Wed, 6 Feb 2019 15:24:54 +0000 (+0000) Subject: Merge "(Automated Tests) All tests passing on Ubuntu 16.04" into devel/master X-Git-Tag: dali_1.4.6~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=10b846b1f907673d1c6639e9298e1acda6f0538c;hp=184e719fa04c4a5bbe171c3be7da133e2a7a0399 Merge "(Automated Tests) All tests passing on Ubuntu 16.04" into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 7a71661..746299b 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -49,6 +49,7 @@ LIST(APPEND TC_SOURCES ../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp + ../dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp ../dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp ../dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp index d72bf17..823c7bb 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -25,6 +25,18 @@ using namespace Dali::Toolkit::Internal; + +void utc_dali_toolkit_texture_manager_startup(void) +{ + setenv( "LOG_TEXTURE_MANAGER", "3", 1 ); + test_return_value = TET_UNDEF; +} + +void utc_dali_toolkit_texture_manager_cleanup(void) +{ + test_return_value = TET_PASS; +} + class TestObserver : public Dali::Toolkit::TextureUploadObserver { public: diff --git a/automated-tests/src/dali-toolkit-styling/CMakeLists.txt b/automated-tests/src/dali-toolkit-styling/CMakeLists.txt index 6b38451..2366711 100644 --- a/automated-tests/src/dali-toolkit-styling/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-styling/CMakeLists.txt @@ -37,6 +37,7 @@ LIST(APPEND TC_SOURCES ../dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp + ../dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp ../dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp diff --git a/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt b/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt index e9ff79a..a5fde09 100644 --- a/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt @@ -26,6 +26,7 @@ LIST(APPEND TC_SOURCES ../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp + ../dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp ../dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp ../dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index bd9848f..1ef55f9 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -104,6 +104,7 @@ LIST(APPEND TC_SOURCES dali-toolkit-test-utils/toolkit-web-engine.cpp dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp dali-toolkit-test-utils/dali-test-suite-utils.cpp + dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp dali-toolkit-test-utils/dummy-control.cpp dali-toolkit-test-utils/layout-utils.cpp dali-toolkit-test-utils/mesh-builder.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp new file mode 100644 index 0000000..94c9530 --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 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. + */ + +#include "dali-toolkit-test-suite-utils.h" + + +std::ostream& operator<<( std::ostream& ostream, Dali::Toolkit::Visual::ResourceStatus status ) +{ + switch(status) + { + case Dali::Toolkit::Visual::ResourceStatus::PREPARING: + { + ostream << "PREPARING"; + break; + } + case Dali::Toolkit::Visual::ResourceStatus::READY: + { + ostream << "READY"; + break; + } + case Dali::Toolkit::Visual::ResourceStatus::FAILED: + { + ostream << "FAILED"; + break; + } + } + return ostream; +} diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h index 32dac4b..013d2c6 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_TEST_SUITE_UTILS_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -18,6 +18,13 @@ * */ +#include +#include + +// Put any toolkit specific operators for DALI_TEST_CHECK template here, before dali-test-suite-utils.h. + +std::ostream& operator<<( std::ostream& ostream, Dali::Toolkit::Visual::ResourceStatus status ); + // INTERNAL INCLUDES #include diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp index 5b8a324..02f3d8f 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp @@ -77,7 +77,7 @@ bool EventThreadCallback::WaitingForTrigger() struct timespec now; clock_gettime( CLOCK_REALTIME, &now ); if( now.tv_nsec < 999900000 ) // 999, 900, 000 - now.tv_nsec += 100000; + now.tv_nsec += 1000; else { now.tv_sec += 1; @@ -124,6 +124,10 @@ bool WaitForEventThreadTrigger( int triggerCount, int timeoutInSeconds ) Dali::CallbackBase::Execute( *callback ); triggerCount--; } + if( triggerCount <= 0 ) + { + break; + } } } clock_gettime( CLOCK_REALTIME, &now ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index 29370b7..7d1ea16 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -1841,6 +1841,8 @@ int UtcDaliImageViewCustomShader(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + Renderer renderer = imageView.GetRendererAt( 0 ); Shader shader2 = renderer.GetShader(); Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM ); @@ -1873,6 +1875,7 @@ int UtcDaliImageViewCustomShader(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); Renderer renderer = imageView.GetRendererAt( 0 ); Shader shader2 = renderer.GetShader(); @@ -1910,6 +1913,7 @@ int UtcDaliImageViewCustomShader(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); Renderer renderer = imageView.GetRendererAt( 0 ); Shader shader2 = renderer.GetShader(); @@ -1947,6 +1951,7 @@ int UtcDaliImageViewCustomShader(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); Renderer renderer = imageView.GetRendererAt( 0 ); Shader shader2 = renderer.GetShader(); @@ -1963,3 +1968,60 @@ int UtcDaliImageViewCustomShader(void) END_TEST; } + + +namespace +{ +static int gFailCounter = 0; +const int MAX_RETRIES(3); + +void ReloadImage(ImageView imageView) +{ + Property::Map imageImmediateLoadingMap; + imageImmediateLoadingMap[ ImageVisual::Property::URL ] = "Non-existant-image.jpg"; + imageImmediateLoadingMap[ ImageVisual::Property::LOAD_POLICY ] = ImageVisual::LoadPolicy::IMMEDIATE; + + tet_infoline("Immediate load an image"); + imageView.SetProperty( ImageView::Property::IMAGE, imageImmediateLoadingMap ); +} + +void ResourceFailedReload( Control control ) +{ + gFailCounter++; + if( gFailCounter < MAX_RETRIES ) + { + ReloadImage(ImageView::DownCast(control)); + } +} +} + +int UtcDaliImageViewReloadFailedOnResourceReadySignal(void) +{ + tet_infoline("Test reloading failed image from within signal handler."); + + ToolkitTestApplication application; + + gFailCounter = 0; + + ImageView imageView = ImageView::New(); + imageView.ResourceReadySignal().Connect( &ResourceFailedReload ); + DALI_TEST_EQUALS( gFailCounter, 0, TEST_LOCATION ); + ReloadImage(imageView); + + // loading started, this waits for the loader thread to complete + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + application.SendNotification(); + + DALI_TEST_EQUALS( gFailCounter, 1, TEST_LOCATION ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + application.SendNotification(); + + DALI_TEST_EQUALS( gFailCounter, 2, TEST_LOCATION ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + application.SendNotification(); + DALI_TEST_EQUALS( gFailCounter, 3, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index 90dd9e7..a15ecf6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,7 @@ void dali_image_visual_cleanup(void) namespace { const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg"; +const char* TEST_BROKEN_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/a-random-nonimage.jpg"; const char* TEST_LARGE_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/tbcol.png"; const char* TEST_SMALL_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png"; const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/themes/tizen_theme/logo.png"; @@ -53,10 +55,15 @@ const char* TEST_ROTATED_IMAGE = TEST_RESOURCE_DIR "/keyboard-Landscape.jpg"; bool gResourceReadySignalFired = false; - +std::vector gReadyIds = {}; void ResourceReadySignal( Control control ) { gResourceReadySignalFired = true; + gReadyIds.push_back(control.GetId()); +} +void ClearReadyIds() +{ + gReadyIds.clear(); } Actor CreateActorWithImageVisual(const Property::Map& map) @@ -2178,3 +2185,97 @@ int UtcDaliImageVisualCustomShader(void) END_TEST; } + + +void ResourceReadyLoadNext( Control control ) +{ + static int callNumber = 0; + + gResourceReadySignalFired = true; + gReadyIds.push_back(control.GetId()); + + if( callNumber == 0 ) + { + DALI_TEST_EQUALS( control.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL), Toolkit::Visual::ResourceStatus::FAILED, TEST_LOCATION ); + + tet_infoline( "Create visual with loaded image from within the signal handler" ); + VisualFactory factory = VisualFactory::Get(); + Visual::Base imageVisual = factory.CreateVisual( TEST_IMAGE_FILE_NAME, ImageDimensions{20,30} ); + + Impl::DummyControl& controlImpl = static_cast(control.GetImplementation()); + controlImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); // This should trigger another signal. + callNumber = 1; + } + else + { + tet_infoline( "3rd signal called" ); + DALI_TEST_CHECK(true); + } +} + +int UtcDaliImageVisualLoadReady01(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageVisualLoadReady01"); + tet_infoline( "First part: Load an image visual for one resource, then another image visual for a second resource."); + tet_infoline( "Second part, In the ready signal for the second image visual, add a 3rd visual with the first URL" ); + tet_infoline( "Should get a ready signal for all three visuals"); + + ClearReadyIds(); + + tet_infoline( "Create a control and connect to resource ready signal" ); + DummyControl actor = DummyControl::New(true); + int actor1Id = actor.GetId(); + actor.ResourceReadySignal().Connect( &ResourceReadySignal); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + actor.SetSize(200.f, 200.f); + Stage::GetCurrent().Add(actor); + + tet_infoline( "Create visual with IMMEDIATE load policy" ); + Visual::Base imageVisual1 = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE ); + + tet_infoline( "Registering visual allows control to get a signal once loaded even if visual not enabled( staged )" ); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual1 ); + + + tet_infoline( "Allow image time to load" ); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + application.SendNotification(); + application.Render(); + + tet_infoline( "Testing texture is loaded and resource ready signal fired" ); + DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION ); + DALI_TEST_EQUALS( gReadyIds[0], actor1Id, TEST_LOCATION ); + + + tet_infoline( "Original control correctly signalled, now testing failing image" ); + + gResourceReadySignalFired = false; // Reset signal check ready for testing next Control + ClearReadyIds(); + + Visual::Base imageVisual2 = CreateVisualWithPolicy( TEST_BROKEN_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE ); + + DummyControl actor2 = DummyControl::New(true); + int actor2Id = actor2.GetId(); + Impl::DummyControl& dummyImpl2 = static_cast(actor2.GetImplementation()); + actor2.ResourceReadySignal().Connect( &ResourceReadyLoadNext); + + tet_infoline( "Registering visual this should trigger the ready signal when the image fails to load" ); + dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual2 ); + + actor2.SetSize(200.f, 200.f); + Stage::GetCurrent().Add(actor2); + + tet_infoline( "Wait for loading thread to finish"); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION ); + + DALI_TEST_EQUALS( gReadyIds[0], actor2Id, TEST_LOCATION); + + tet_infoline( "Check for 3rd signal"); + application.SendNotification(); + DALI_TEST_EQUALS( gReadyIds.size(), 2, TEST_LOCATION ); + DALI_TEST_EQUALS( gReadyIds[1], actor2Id, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp index 89a95ba..72370db 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -26,7 +26,6 @@ using namespace Dali::Toolkit; namespace { - } // namespace @@ -152,6 +151,3 @@ int UtcDaliTextureManagerRemoveN(void) END_TEST; } - - - diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 3f4e763..bbef5e4 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -811,6 +811,7 @@ void ImageVisual::DoSetOffStage( Actor& actor ) if( mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED ) { RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; } if( mImageUrl.IsValid() ) diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 1ea95a9..7847924 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -79,6 +79,16 @@ namespace #ifdef DEBUG_ENABLED Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_TEXTURE_MANAGER" ); + +#define GET_LOAD_STATE_STRING( loadState ) \ + loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : \ + loadState == TextureManager::LOADING ? "LOADING" : \ + loadState == TextureManager::LOAD_FINISHED ? "LOAD_FINISHED" : \ + loadState == TextureManager::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \ + loadState == TextureManager::UPLOADED ? "UPLOADED" : \ + loadState == TextureManager::CANCELLED ? "CANCELLED" : \ + loadState == TextureManager::LOAD_FAILED ? "LOAD_FAILED" : "Unknown" + #endif const uint32_t DEFAULT_ATLAS_SIZE( 1024u ); ///< This size can fit 8 by 8 images of average size 128 * 128 @@ -117,8 +127,10 @@ TextureManager::TextureManager() mAsyncRemoteLoaders( GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ), mExternalTextures(), mLifecycleObservers(), + mLoadQueue(), mBrokenImageUrl(""), - mCurrentTextureId( 0 ) + mCurrentTextureId( 0 ), + mQueueLoadFlag(false) { } @@ -242,13 +254,18 @@ TextureSet TextureManager::LoadTexture( } TextureManager::LoadState loadState = GetTextureStateInternal( textureId ); - loadingStatus = ( loadState == TextureManager::LOADING ); - if( loadState == TextureManager::UPLOADED ) { // UploadComplete has already been called - keep the same texture set textureSet = GetTextureSet( textureId ); } + + // If we are loading the texture, or waiting for the ready signal handler to complete, inform + // caller that they need to wait. + loadingStatus = ( loadState == TextureManager::LOADING || + loadState == TextureManager::NOT_STARTED || + mQueueLoadFlag ); + } else { @@ -345,7 +362,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( ++( mTextureInfoContainer[ cacheIndex ].referenceCount ); } textureId = mTextureInfoContainer[ cacheIndex ].textureId; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId ); } @@ -360,7 +377,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( preMultiply ) ); cacheIndex = mTextureInfoContainer.size() - 1u; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId ); } @@ -372,11 +389,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( textureInfo.storageType = storageType; textureInfo.orientationCorrection = orientationCorrection; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n", - textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : - textureInfo.loadState == TextureManager::LOADING ? "LOADING" : - textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" : - textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s\n", + GET_LOAD_STATE_STRING(textureInfo.loadState ) ); // Force reloading of texture by setting loadState unless already loading or cancelled. if ( TextureManager::ReloadPolicy::FORCED == reloadPolicy && TextureManager::LOADING != textureInfo.loadState && @@ -394,8 +408,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( case TextureManager::LOAD_FAILED: // Failed notifies observer which then stops observing. case TextureManager::NOT_STARTED: { - LoadTexture( textureInfo ); - ObserveTexture( textureInfo, observer ); + LoadOrQueueTexture( textureInfo, observer ); // If called inside NotifyObservers, queues until afterwards break; } case TextureManager::LOADING: @@ -407,11 +420,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( { if( observer ) { - // The Texture has already loaded. The other observers have already been notified. - // We need to send a "late" loaded notification for this observer. - observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, - textureInfo.useAtlas, textureInfo.atlasRect, - textureInfo.preMultiplied ); + LoadOrQueueTexture( textureInfo, observer ); } break; } @@ -440,12 +449,10 @@ void TextureManager::Remove( const TextureManager::TextureId textureId ) { TextureInfo& textureInfo( mTextureInfoContainer[ textureInfoIndex ] ); - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::Remove(%d) cacheIdx:%d loadState:%s\n", - textureId, textureInfoIndex, - textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : - textureInfo.loadState == TextureManager::LOADING ? "LOADING" : - textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" : - textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, + "TextureManager::Remove(%d) url:%s\n cacheIdx:%d loadState:%s\n", + textureId, textureInfo.url.GetUrl().c_str(), + textureInfoIndex, GET_LOAD_STATE_STRING( textureInfo.loadState ) ); // Decrement the reference count and check if this is the last user of this Texture. if( --textureInfo.referenceCount <= 0 ) @@ -624,32 +631,101 @@ void TextureManager::RemoveObserver( TextureManager::LifecycleObserver& observer DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End()); } +void TextureManager::LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) +{ + switch( textureInfo.loadState ) + { + case NOT_STARTED: + case LOAD_FAILED: + { + if( mQueueLoadFlag ) + { + QueueLoadTexture( textureInfo, observer ); + } + else + { + LoadTexture( textureInfo, observer ); + } + break; + } + case LOADING: + case UPLOADED: + { + if( mQueueLoadFlag ) + { + QueueLoadTexture( textureInfo, observer ); + } + else + { + // The Texture has already loaded. The other observers have already been notified. + // We need to send a "late" loaded notification for this observer. + observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, + textureInfo.useAtlas, textureInfo.atlasRect, + textureInfo.preMultiplied ); + } + } + case CANCELLED: + case LOAD_FINISHED: + case WAITING_FOR_MASK: + { + break; + } + } +} + +void TextureManager::QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) +{ + auto textureId = textureInfo.textureId; + mLoadQueue.PushBack( LoadQueueElement( textureId, observer) ); +} -bool TextureManager::LoadTexture( TextureInfo& textureInfo ) +void TextureManager::LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) { - bool success = true; + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::LoadTexture(): url:%s sync:%s\n", + textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously?"T":"F" ); - if( textureInfo.loadState == NOT_STARTED ) + textureInfo.loadState = LOADING; + if( !textureInfo.loadSynchronously ) { - textureInfo.loadState = LOADING; + auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; + auto loadingHelperIt = loadersContainer.GetNext(); + DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); + loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, + textureInfo.desiredSize, textureInfo.fittingMode, + textureInfo.samplingMode, textureInfo.orientationCorrection ); + } + ObserveTexture( textureInfo, observer ); +} - if( !textureInfo.loadSynchronously ) +void TextureManager::ProcessQueuedTextures() +{ + for( auto&& element : mLoadQueue ) + { + int cacheIndex = GetCacheIndexFromId( element.mTextureId ); + if( cacheIndex != INVALID_CACHE_INDEX ) { - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; - auto loadingHelperIt = loadersContainer.GetNext(); - DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); - loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, - textureInfo.desiredSize, textureInfo.fittingMode, - textureInfo.samplingMode, textureInfo.orientationCorrection ); + TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] ); + if( textureInfo.loadState == UPLOADED ) + { + element.mObserver->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, + textureInfo.useAtlas, textureInfo.atlasRect, + textureInfo.preMultiplied ); + } + else + { + LoadTexture( textureInfo, element.mObserver ); + } } } - - return success; + mLoadQueue.Clear(); } void TextureManager::ObserveTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) { + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::ObserveTexture(): url:%s observer:%p\n", + textureInfo.url.GetUrl().c_str(), observer ); + if( observer ) { textureInfo.observerList.PushBack( observer ); @@ -673,7 +749,9 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo { TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] ); - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " CacheIndex:%d LoadState: %d\n", cacheIndex, textureInfo.loadState ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, + " textureId:%d Url:%s CacheIndex:%d LoadState: %d\n", + textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, textureInfo.loadState ); if( textureInfo.loadState != CANCELLED ) { @@ -788,12 +866,11 @@ void TextureManager::ApplyMask( } } - void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo ) { if( textureInfo.useAtlas != USE_ATLAS ) { - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId ); // If the texture doesn't have an alpha channel, can't pre-multiply it. // Ensure that we don't change the load parameter (it's used for hashing), and instead set @@ -828,53 +905,50 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) // If there is an observer: Notify the load is complete, whether successful or not, // and erase it from the list - unsigned int observerCount = textureInfo.observerList.Count(); TextureInfo* info = &textureInfo; - while( observerCount ) + mQueueLoadFlag = true; + + while( info->observerList.Count() ) { TextureUploadObserver* observer = info->observerList[0]; // During UploadComplete() a Control ResourceReady() signal is emitted. // During that signal the app may add remove /add Textures (e.g. via - // ImageViews). At this point no more observers can be added to the - // observerList, because textureInfo.loadState = UPLOADED. However it is - // possible for observers to be removed, hence we check the observer list - // count every iteration. - - // The reference to the textureInfo struct can also become invalidated, - // because new load requests can modify the mTextureInfoContainer list - // (e.g. if more requests are pushed back it can cause the list to be - // resized invalidating the reference to the TextureInfo ). + // ImageViews). + // It is possible for observers to be removed from the observer list, + // and it is also possible for the mTextureInfoContainer to be modified, + // invalidating the reference to the textureInfo struct. + // Texture load requests for the same URL are deferred until the end of this + // method. + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "NotifyObservers() url:%s loadState:%s\n", + textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) ); + observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, info->preMultiplied ); observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed ); - // Get the textureInfo from the container again as it may have been - // invalidated, - + // Get the textureInfo from the container again as it may have been invalidated. int textureInfoIndex = GetCacheIndexFromId( textureId ); if( textureInfoIndex == INVALID_CACHE_INDEX) { - return; // texture has been removed - can stop. + break; // texture has been removed - can stop. } - info = &mTextureInfoContainer[ textureInfoIndex ]; - observerCount = info->observerList.Count(); - if ( observerCount > 0 ) + + // remove the observer that was just triggered if it's still in the list + for( TextureInfo::ObserverListType::Iterator j = info->observerList.Begin(); j != info->observerList.End(); ++j ) { - // remove the observer that was just triggered if it's still in the list - for( TextureInfo::ObserverListType::Iterator j = info->observerList.Begin(); j != info->observerList.End(); ++j ) + if( *j == observer ) { - if( *j == observer ) - { - info->observerList.Erase( j ); - observerCount--; - break; - } + info->observerList.Erase( j ); + break; } } } + + mQueueLoadFlag = false; + ProcessQueuedTextures(); } TextureManager::TextureId TextureManager::GenerateUniqueTextureId() diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 6df17c6..502cf11 100755 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -424,6 +424,8 @@ private: typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching. + // Structs: + /** * @brief This struct is used to manage the life-cycle of Texture loading and caching. */ @@ -495,7 +497,20 @@ private: bool preMultiplied:1; ///< true if the image's color was multiplied by it's alpha }; - // Structs: + /** + * Structure to hold info about a texture load queued during NotifyObservers + */ + struct LoadQueueElement + { + LoadQueueElement( TextureId textureId, TextureUploadObserver* observer ) + : mTextureId( textureId ), + mObserver( observer ) + { + } + + TextureId mTextureId; ///< The texture id of the requested load. + TextureUploadObserver* mObserver; ///< Observer of texture load. + }; /** * Struct to hold information about a requested Async load. @@ -519,16 +534,35 @@ private: typedef std::vector TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures /** + * @brief Initiate a load or queue load if NotifyObservers is invoking callbacks + * @param[in] textureInfo The TextureInfo struct associated with the Texture + * @param[in] observer The observer wishing to observe the texture upload + */ + void LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ); + + /** + * @brief Queue a texture load to be subsequently handled by ProcessQueuedTextures. + * @param[in] textureInfo The TextureInfo struct associated with the Texture + * @param[in] observer The observer wishing to observe the texture upload + */ + void QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ); + + /** * @brief Used internally to initiate a load. * @param[in] textureInfo The TextureInfo struct associated with the Texture - * @return True if the load was initiated + * @param[in] observer The observer wishing to observe the texture upload + */ + void LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ); + + /** + * @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks. */ - bool LoadTexture( TextureInfo& textureInfo ); + void ProcessQueuedTextures(); /** * Add the observer to the observer list * @param[in] textureInfo The TextureInfo struct associated with the texture - * observer The observer wishing to observe the texture upload + * @param[in] observer The observer wishing to observe the texture upload */ void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer ); @@ -747,8 +781,10 @@ private: // Member Variables: RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads std::vector< ExternalTextureInfo > mExternalTextures; ///< Externally provided textures Dali::Vector mLifecycleObservers; ///< Lifecycle observers of texture manager + Dali::Vector mLoadQueue; ///< Queue of textures to load after NotifyObservers std::string mBrokenImageUrl; ///< Broken image url TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation + bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued. }; diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.cpp b/dali-toolkit/internal/visuals/visual-factory-impl.cpp index d30729b..2c8183c 100644 --- a/dali-toolkit/internal/visuals/visual-factory-impl.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-impl.cpp @@ -60,6 +60,10 @@ namespace Internal namespace { +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS"); +#endif + BaseHandle Create() { BaseHandle handle = Toolkit::VisualFactory::Get(); @@ -273,9 +277,19 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property } } + DALI_LOG_INFO( gLogFilter, Debug::Concise, "VisualFactory::CreateVisual( VisualType:%s %s%s)\n", + Scripting::GetEnumerationName( visualType, + VISUAL_TYPE_TABLE, + VISUAL_TYPE_TABLE_COUNT ), + visualType==Toolkit::DevelVisual::IMAGE?"url:":"", + visualType==Toolkit::DevelVisual::IMAGE ? + propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME)->Get().c_str() + :"" ); + + if( !visualPtr ) { - DALI_LOG_ERROR( "Renderer type unknown\n" ); + DALI_LOG_ERROR( "VisualType unknown\n" ); } if( mDebugEnabled && visualType != Toolkit::DevelVisual::WIREFRAME ) diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp index 4027521..0cb665c 100644 --- a/dali-toolkit/public-api/dali-toolkit-version.cpp +++ b/dali-toolkit/public-api/dali-toolkit-version.cpp @@ -31,7 +31,7 @@ namespace Toolkit const unsigned int TOOLKIT_MAJOR_VERSION = 1; const unsigned int TOOLKIT_MINOR_VERSION = 4; -const unsigned int TOOLKIT_MICRO_VERSION = 4; +const unsigned int TOOLKIT_MICRO_VERSION = 5; const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__; #ifdef DEBUG_ENABLED diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index b6e3c76..fabfa6b 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -1,6 +1,6 @@ Name: dali-toolkit Summary: Dali 3D engine Toolkit -Version: 1.4.4 +Version: 1.4.5 Release: 1 Group: System/Libraries License: Apache-2.0 and BSD-3-Clause and MIT