2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include <dali/dali.h>
22 #include <dali-test-suite-utils.h>
23 #include "slp-platform-abstraction.h"
24 #include "resource-collector.h"
27 using namespace Dali::Integration;
28 using namespace Dali::Internal::Platform;
33 * The number of loads issued in test cases is a multiple of this. The higher it
34 * is, the more the tests stress the system but the longer they take to run.
35 * A value of 1000 is enough to make load tests take tens of seconds each
37 const unsigned NUM_LOAD_GROUPS_TO_ISSUE = 200;
40 * The number of loads to issue when they will be cancelled.
41 * Cancelled loads are cheap so we do a lot.
43 const unsigned NUM_CANCELLED_LOAD_GROUPS_TO_ISSUE = NUM_LOAD_GROUPS_TO_ISSUE * 10;
45 /** The number of times to ask for resource load status. */
46 const unsigned MAX_NUM_RESOURCE_TRIES = 5;
48 /** Images that should load without issue. */
49 const char* const VALID_IMAGES[] = {
50 TEST_IMAGE_DIR "/frac.jpg",
51 TEST_IMAGE_DIR "/frac.24.bmp",
52 TEST_IMAGE_DIR "/frac.png",
53 TEST_IMAGE_DIR "/interlaced.gif",
54 TEST_IMAGE_DIR "/pattern.gif"
56 const unsigned NUM_VALID_IMAGES = sizeof(VALID_IMAGES) / sizeof(VALID_IMAGES[0]);
58 ///@ToDo: Add valid ktx, ico, and wbmp image examples.
60 /** Live platform abstraction recreated for each test case. */
61 Integration::PlatformAbstraction * gAbstraction = 0;
63 /** A variety of ImageAttributes to reach different code paths that have embedded code paths. */
64 std::vector<ImageAttributes> gCancelAttributes;
68 void utc_dali_loading_startup(void)
70 test_return_value = TET_UNDEF;
71 gAbstraction = CreatePlatformAbstraction();
73 // Setup some ImageAttributes to engage post-processing stages:
75 ImageAttributes scaleToFillAttributes;
76 scaleToFillAttributes.SetScalingMode( ImageAttributes::ScaleToFill );
77 scaleToFillAttributes.SetSize( 160, 120 );
78 gCancelAttributes.push_back( scaleToFillAttributes );
80 // Hit the derived dimensions code:
81 ImageAttributes scaleToFillAttributesDeriveWidth = scaleToFillAttributes;
82 scaleToFillAttributesDeriveWidth.SetSize( 0, 120 );
83 gCancelAttributes.push_back( scaleToFillAttributesDeriveWidth );
85 ImageAttributes scaleToFillAttributesDeriveHeight = scaleToFillAttributes;
86 scaleToFillAttributesDeriveHeight.SetSize( 160, 0 );
87 gCancelAttributes.push_back( scaleToFillAttributesDeriveHeight );
89 // Try to push a tall crop:
90 ImageAttributes scaleToFillAttributesTall = scaleToFillAttributes;
91 scaleToFillAttributesTall.SetSize( 160, 480 );
92 ImageAttributes scaleToFillAttributesTall2 = scaleToFillAttributes;
93 scaleToFillAttributesTall2.SetSize( 160, 509 );
94 ImageAttributes scaleToFillAttributesTall3 = scaleToFillAttributes;
95 scaleToFillAttributesTall3.SetSize( 37, 251 );
96 gCancelAttributes.push_back( scaleToFillAttributesTall );
97 gCancelAttributes.push_back( scaleToFillAttributesTall2 );
98 gCancelAttributes.push_back( scaleToFillAttributesTall3 );
100 // Try to push a wide crop:
101 ImageAttributes scaleToFillAttributesWide = scaleToFillAttributes;
102 scaleToFillAttributesWide.SetSize( 320, 60 );
103 ImageAttributes scaleToFillAttributesWide2 = scaleToFillAttributes;
104 scaleToFillAttributesWide2.SetSize( 317, 60 );
105 ImageAttributes scaleToFillAttributesWide3 = scaleToFillAttributes;
106 scaleToFillAttributesWide3.SetSize( 317, 53 );
107 gCancelAttributes.push_back( scaleToFillAttributesWide );
108 gCancelAttributes.push_back( scaleToFillAttributesWide2 );
109 gCancelAttributes.push_back( scaleToFillAttributesWide3 );
111 ImageAttributes shrinkToFitAttributes = scaleToFillAttributes;
112 shrinkToFitAttributes.SetScalingMode( ImageAttributes::ShrinkToFit );
113 gCancelAttributes.push_back( shrinkToFitAttributes );
115 ImageAttributes fitWidthAttributes = scaleToFillAttributes;
116 fitWidthAttributes.SetScalingMode( ImageAttributes::FitWidth );
117 gCancelAttributes.push_back( fitWidthAttributes );
119 ImageAttributes fitHeightAttributes = scaleToFillAttributes;
120 fitHeightAttributes.SetScalingMode( ImageAttributes::FitHeight );
121 gCancelAttributes.push_back( fitHeightAttributes );
123 ///@ToDo: Add attribute variants for all scale modes.
125 // Pad the array to a prime number to mitigate any accidental periodic
126 // patterns in which image file has which attributes applied to its load:
128 const float lastUniques = gCancelAttributes.size() - 0.001f;
129 while( gCancelAttributes.size() < 61u )
131 gCancelAttributes.push_back( gCancelAttributes[unsigned(drand48() * lastUniques)] );
135 void utc_dali_loading_cleanup(void)
140 test_return_value = TET_PASS;
143 // Positive test case for loading. Load lots and be sure it has succeeded.
144 int UtcDaliLoadCompletion(void)
146 tet_printf("Running load completion test \n");
148 DALI_ASSERT_ALWAYS( gAbstraction != 0 );
150 // Start a bunch of loads that should work:
152 const Dali::ImageAttributes attributes;
153 const Dali::Integration::BitmapResourceType bitmapResourceType( attributes );
154 Dali::Integration::LoadResourcePriority priority = Dali::Integration::LoadPriorityNormal;
155 unsigned loadsLaunched = 0;
157 for( unsigned loadGroup = 0; loadGroup < NUM_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
159 for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
161 gAbstraction->LoadResource( ResourceRequest( loadGroup * NUM_VALID_IMAGES + validImage + 1, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
163 loadsLaunched += NUM_VALID_IMAGES;
166 // Drain the completed loads:
168 Dali::Internal::Platform::ResourceCollector resourceSink;
170 for( unsigned i = 0; i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched; ++i )
172 tet_printf( "Draining sleep %u, at total completion count %u of %u.\n", i, resourceSink.mGrandTotalCompletions, loadsLaunched );
173 usleep( 1200 * 1000 );
174 gAbstraction->GetResources( resourceSink );
177 // Check the loads completed as expected:
179 tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
180 DALI_TEST_CHECK( loadsLaunched == resourceSink.mGrandTotalCompletions );
181 DALI_TEST_CHECK( loadsLaunched == resourceSink.mSuccessCounts.size() );
182 DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
184 // Check that each success was reported exactly once:
185 for( ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
187 DALI_TEST_CHECK( it->second == 1u );
194 * @brief Test case for load cancellation.
196 * Load lots of images in batches, cancelling all in a batch after a small delay to
197 * allow the first of a batch to be launched before cancellation starts.
198 * Assert that all loads issued are either completed or cancelled.
200 int UtcDaliCancelAllLoads(void)
202 tet_printf( "Running load cancel-all test.\n" );
204 DALI_ASSERT_ALWAYS( gAbstraction != 0 );
206 // Start a bunch of loads that should work:
208 Dali::Integration::LoadResourcePriority priority = LoadPriorityNormal;
209 unsigned loadsLaunched = 0;
211 for( unsigned loadGroup = 0; loadGroup < NUM_CANCELLED_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
213 // Issue load requests for a batch of images:
214 for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
216 const BitmapResourceType bitmapResourceType( gCancelAttributes[ loadsLaunched % gCancelAttributes.size() ] );
217 const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
218 gAbstraction->LoadResource( ResourceRequest( resourceId, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
222 // Let the first image in the batch start to load:
223 usleep( 5000 ); // This number is tuned. Turn it up too much and all loads will complete and the test will take so long it seems to hang.
225 // Cancel all the launched loads from oldest to newest:
226 for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
228 const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
229 gAbstraction->CancelLoad( resourceId, ResourceBitmap );
233 // Drain the completed loads:
234 Dali::Internal::Platform::ResourceCollector resourceSink;
236 unsigned lastCompletions = -1;
237 for( unsigned i = 0; i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched && resourceSink.mGrandTotalCompletions != lastCompletions; ++i )
239 lastCompletions = resourceSink.mGrandTotalCompletions;
240 gAbstraction->GetResources( resourceSink );
241 tet_printf( "Draining sleep %u, at total completion count %u of %u.\n", i, resourceSink.mGrandTotalCompletions, loadsLaunched );
242 usleep( 100 * 1000 );
245 // Check the loads completed as expected:
247 tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
248 DALI_TEST_CHECK( loadsLaunched > resourceSink.mGrandTotalCompletions );
249 DALI_TEST_CHECK( loadsLaunched > resourceSink.mSuccessCounts.size() );
250 DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
252 // Check that each success was reported exactly once:
253 for( ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
255 DALI_TEST_CHECK( it->second == 1u );
262 * @brief Test case for load cancellation.
264 * Load lots, cancel a subset and be sure the wrong loads are never cancelled
265 * and that all loads issued are either completed or cancelled.
267 int UtcDaliCancelSomeLoads(void)
269 tet_printf( "Running load cancel load subset test.\n" );
271 DALI_ASSERT_ALWAYS( gAbstraction != 0 );
273 // Start a bunch of loads that should work:
275 Dali::Integration::LoadResourcePriority priority = LoadPriorityNormal;
276 unsigned loadsLaunched = 0;
278 std::set<Integration::ResourceId> cancelledLoadSet;
280 for( unsigned loadGroup = 0; loadGroup < NUM_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
282 // Issue load requests for a batch of images:
283 for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
285 const BitmapResourceType bitmapResourceType( gCancelAttributes[ loadsLaunched % gCancelAttributes.size() ] );
286 const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
287 gAbstraction->LoadResource( ResourceRequest( resourceId, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
291 // Let the first image in the batch start to load so we can try to cancel it in-flight:
293 ///@Note: The log should show cancellations of many in-flight loads in desktop builds with info-level logging enabled (e.g., "INFO: DALI: : CheckForCancellation: Cancelled in-flight resource (21)."). If it doesn't, the above delay may need to be adjusted.
295 // Cancel just two loads (hopefully one in-flight and one queued):
297 // Cancel first load, hopefully while it is in-flight:
298 const ResourceId cancelledInFlight = loadGroup * NUM_VALID_IMAGES + 1;
299 gAbstraction->CancelLoad( cancelledInFlight, ResourceBitmap );
300 cancelledLoadSet.insert( cancelledInFlight );
302 // Cancel second load, that is still queued:
303 const ResourceId cancelledFromQueue = loadGroup * NUM_VALID_IMAGES + NUM_VALID_IMAGES;
304 gAbstraction->CancelLoad( cancelledFromQueue, ResourceBitmap );
305 cancelledLoadSet.insert( cancelledFromQueue );
308 // Drain the completed loads:
310 Dali::Internal::Platform::ResourceCollector resourceSink;
312 unsigned lastCompletions = -1;
313 for( unsigned i = 0; i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched && resourceSink.mGrandTotalCompletions != lastCompletions; ++i )
315 lastCompletions = resourceSink.mGrandTotalCompletions;
316 gAbstraction->GetResources( resourceSink );
317 tet_printf( "Draining sleep %u, at total completion count %u of %u.\n", i, resourceSink.mGrandTotalCompletions, loadsLaunched );
318 usleep( 100 * 1000 );
321 // Check the loads completed as expected:
323 tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
324 DALI_TEST_CHECK( loadsLaunched >= resourceSink.mGrandTotalCompletions );
325 DALI_TEST_CHECK( loadsLaunched >= resourceSink.mSuccessCounts.size() );
326 DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
328 // Check that if an image was not loaded, it is one of the ones that was cancelled:
329 // This is the main point of this test case.
330 for( unsigned resourceId = 1; resourceId <= NUM_LOAD_GROUPS_TO_ISSUE * NUM_VALID_IMAGES; ++resourceId )
332 if( resourceSink.mCompletionStatuses.find( resourceId ) == resourceSink.mCompletionStatuses.end() )
334 DALI_TEST_CHECK( cancelledLoadSet.find( resourceId ) != cancelledLoadSet.end() );
338 // Check that each success was reported exactly once:
339 for(ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
341 DALI_TEST_CHECK( it->second == 1u );