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.
19 #include "resource-loader.h"
22 #include <boost/thread.hpp>
28 #include <dali/integration-api/bitmap.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/integration-api/resource-cache.h>
31 #include <dali/public-api/common/dali-common.h>
32 #include <dali/devel-api/common/set-wrapper.h>
33 #include <dali/public-api/math/vector2.h>
34 #include "resource-requester-base.h"
35 #include "resource-bitmap-requester.h"
36 #include "resource-shader-requester.h"
37 #include "debug/resource-loader-debug.h"
41 * A macro to expand an argument to a compile time constant string literal.
42 * Wrapping the stringify in an outer macro, means that any macro passed as
43 * "x" will be expanded before being turned into a string.
44 * Use this for example to turn the current line number into a string:
45 * puts("The current line number is " DALI_TO_STRING(__LINE__) ".");
47 #define DALI_TO_STRING_INNER(x) #x
48 #define DALI_TO_STRING(x) DALI_TO_STRING_INNER(x)
50 using namespace Dali::Integration;
52 using boost::unique_lock;
57 namespace TizenPlatform
63 } // unnamed namespace
66 struct ResourceLoader::ResourceLoaderImpl
68 typedef std::pair<ResourceId, ResourceRequest> RequestStorePair;
69 typedef std::map<ResourceId, ResourceRequest> RequestStore;
70 typedef RequestStore::iterator RequestStoreIter;
72 typedef std::queue<LoadedResource> LoadedQueue;
73 typedef std::queue<SavedResource> SavedQueue;
74 typedef std::queue<FailedResource> FailedQueue;
76 typedef std::pair<ResourceTypeId, ResourceRequesterBase*> RequestHandlerPair;
77 typedef std::map<ResourceTypeId, ResourceRequesterBase*> RequestHandlers;
78 typedef RequestHandlers::iterator RequestHandlersIter;
80 boost::mutex mQueueMutex; ///< used to synchronize access to mLoadedQueue, mSavedQueue and mFailedQueue
81 LoadedQueue mPartiallyLoadedQueue; ///< Partially complete load requests notifications are stored here until fetched by core
82 LoadedQueue mLoadedQueue; ///< Completed load requests notifications are stored here until fetched by core
83 SavedQueue mSavedQueue; ///< Completed save request notifications are stored here until fetched by core
84 FailedQueue mFailedLoads; ///< Failed load request notifications are stored here until fetched by core
85 FailedQueue mFailedSaves; ///< Failed save request notifications are stored here until fetched by core
87 RequestHandlers mRequestHandlers;
88 RequestStore mStoredRequests; ///< Used to store load requests until loading is completed
90 ResourceLoaderImpl( ResourceLoader* loader )
92 mRequestHandlers.insert(std::make_pair(ResourceBitmap, new ResourceBitmapRequester(*loader)));
93 mRequestHandlers.insert(std::make_pair(ResourceShader, new ResourceShaderRequester(*loader)));
98 // Delete resource handlers
99 for( RequestHandlersIter it = mRequestHandlers.begin(); it != mRequestHandlers.end(); ++it )
101 ResourceRequesterBase* requestBase = it->second;
108 // Pause all the request handlers:
109 for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end; ++it )
111 ResourceRequesterBase * const requester = it->second;
121 // Wake up all the request handlers:
122 for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end; ++it )
124 ResourceRequesterBase * const requester = it->second;
132 ResourceRequesterBase* GetRequester(ResourceTypeId typeId)
134 ResourceRequesterBase* requestHandler = NULL;
135 RequestHandlersIter iter = mRequestHandlers.find(typeId);
136 if(iter != mRequestHandlers.end())
138 requestHandler = iter->second;
140 DALI_ASSERT_DEBUG(requestHandler && "All resource types should have a requester defined for them.");
141 return requestHandler;
144 void LoadResource(const ResourceRequest& request)
146 // Store resource request for partial loaders. Will get cleaned up after load complete has finished
147 StoreRequest(request);
149 ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
152 ResourceRequest* storedRequest = GetRequest(request.GetId());
153 if( storedRequest != NULL )
155 requester->LoadResource(*storedRequest); // Pass in stored request
160 DALI_LOG_ERROR( "Unknown resource type (%u) with path \"%s\" in load request.\n", request.GetType()->id, request.GetPath().c_str() );
161 DALI_ASSERT_DEBUG( 0 == "Unknown resource type in load request at " __FILE__ ", line " DALI_TO_STRING(__LINE__) ".\n" );
165 void SaveResource(const ResourceRequest& request)
167 ResourceRequesterBase* requester = GetRequester( request.GetType()->id );
170 requester->SaveResource( request );
174 void CancelLoad(ResourceId id, ResourceTypeId typeId)
176 ResourceRequesterBase* requester = GetRequester(typeId);
179 requester->CancelLoad( id, typeId );
184 LoadStatus LoadFurtherResources( LoadedResource partialResource )
186 LoadStatus loadStatus = RESOURCE_LOADING;
187 RequestStoreIter iter = mStoredRequests.find(partialResource.id);
189 if( mStoredRequests.end() != iter ) // else cancelled. Ignore response
191 ResourceRequest& request = iter->second;
192 ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
195 loadStatus = requester->LoadFurtherResources( request, partialResource );
198 DALI_LOG_INFO(gLoaderFilter, Debug::General, "ResourceLoader::LoadFurtherResources( ID:%u complete: %s)\n", request.GetId(), loadStatus==RESOURCE_LOADING?"Loading":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE" );
201 if( loadStatus == RESOURCE_COMPLETELY_LOADED )
203 ClearRequest( partialResource.id );
211 // TODO - not used - remove?
212 DALI_ASSERT_DEBUG( 0 == "IsLoading() Is not implemented so don't call it." );
216 void GetResources(ResourceCache& cache)
218 // Fill the resource cache
220 unique_lock<mutex> lock(mQueueMutex);
222 // iterate through the partially loaded resources
223 while (!mPartiallyLoadedQueue.empty())
225 LoadedResource loaded( mPartiallyLoadedQueue.front() );
226 mPartiallyLoadedQueue.pop();
227 LoadStatus loadStatus = LoadFurtherResources( loaded );
228 cache.LoadResponse( loaded.id, loaded.type, loaded.resource, loadStatus );
231 // iterate through the successfully loaded resources
232 while (!mLoadedQueue.empty())
234 LoadedResource loaded( mLoadedQueue.front() );
236 ClearRequest( loaded.id );
237 cache.LoadResponse( loaded.id, loaded.type, loaded.resource, RESOURCE_COMPLETELY_LOADED );
240 // iterate through the successfully saved resources
241 while (!mSavedQueue.empty())
243 SavedResource saved(mSavedQueue.front());
245 cache.SaveComplete(saved.id, saved.type);
248 // iterate through the resources which failed to load
249 while (!mFailedLoads.empty())
251 FailedResource failed(mFailedLoads.front());
253 ClearRequest(failed.id);
254 cache.LoadFailed(failed.id, failed.failureType);
257 // iterate through the resources which failed to save
258 while (!mFailedSaves.empty())
260 FailedResource failed(mFailedSaves.front());
262 cache.SaveFailed(failed.id, failed.failureType);
266 void AddPartiallyLoadedResource( LoadedResource& resource)
268 // Lock the LoadedQueue to store the loaded resource
269 unique_lock<mutex> lock(mQueueMutex);
271 mPartiallyLoadedQueue.push( resource );
274 void AddLoadedResource(LoadedResource& resource)
276 // Lock the LoadedQueue to store the loaded resource
277 unique_lock<mutex> lock(mQueueMutex);
279 mLoadedQueue.push( resource );
282 void AddSavedResource(SavedResource& resource)
284 // Lock the SavedQueue to store the loaded resource
285 unique_lock<mutex> lock(mQueueMutex);
287 mSavedQueue.push(resource);
290 void AddFailedLoad(FailedResource& resource)
292 // Lock the FailedQueue to store the failed resource information
293 unique_lock<mutex> lock(mQueueMutex);
295 mFailedLoads.push(resource);
298 void AddFailedSave(FailedResource& resource)
300 // Lock the FailedQueue to store the failed resource information
301 unique_lock<mutex> lock(mQueueMutex);
303 mFailedSaves.push(resource);
306 void StoreRequest( const ResourceRequest& request )
308 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: StoreRequest(id:%u)\n", request.GetId());
309 mStoredRequests.insert( RequestStorePair( request.GetId(), request ) ); // copy request as value type
312 ResourceRequest* GetRequest( ResourceId id )
314 ResourceRequest* found(NULL);
315 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: GetRequest(id:%u)\n", id);
316 RequestStoreIter iter = mStoredRequests.find( id );
317 if( mStoredRequests.end() != iter )
319 found = &iter->second;
324 void ClearRequest( ResourceId resourceId )
326 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: ClearRequest(id:%u)\n", resourceId);
327 RequestStoreIter iter = mStoredRequests.find( resourceId );
328 if( mStoredRequests.end() != iter ) // Can't assert here - cancel load may cross with load failed
330 mStoredRequests.erase( iter );
335 /********************************************************************************/
336 /**************************** RESOURCE LOADER METHODS ************************/
337 /********************************************************************************/
338 ResourceLoader::ResourceLoader()
339 : mTerminateThread(0)
341 mImpl = new ResourceLoaderImpl( this );
344 ResourceLoader::~ResourceLoader()
346 // Flag that the ResourceLoader is exiting
347 (void)__sync_or_and_fetch( &mTerminateThread, -1 );
352 void ResourceLoader::Pause()
357 void ResourceLoader::Resume()
362 bool ResourceLoader::IsTerminating()
364 return __sync_fetch_and_or( &mTerminateThread, 0 );
367 void ResourceLoader::GetResources(ResourceCache& cache)
369 mImpl->GetResources( cache );
372 /********************************************************************************/
373 /************************** CALLED FROM LOADER THREADS **********************/
374 /********************************************************************************/
376 void ResourceLoader::AddPartiallyLoadedResource( LoadedResource& resource)
378 mImpl->AddPartiallyLoadedResource( resource );
381 void ResourceLoader::AddLoadedResource(LoadedResource& resource)
383 mImpl->AddLoadedResource( resource );
386 void ResourceLoader::AddSavedResource(SavedResource& resource)
388 mImpl->AddSavedResource( resource );
391 void ResourceLoader::AddFailedLoad(FailedResource& resource)
393 mImpl->AddFailedLoad( resource );
396 void ResourceLoader::AddFailedSave(FailedResource& resource)
398 mImpl->AddFailedSave( resource );
401 /********************************************************************************/
402 /********************* CALLED FROM PLATFORM ABSTRACTION **********************/
403 /********************************************************************************/
405 void ResourceLoader::LoadResource(const ResourceRequest& request)
407 mImpl->LoadResource(request);
410 void ResourceLoader::SaveResource(const ResourceRequest& request)
412 mImpl->SaveResource(request);
415 void ResourceLoader::CancelLoad(ResourceId id, ResourceTypeId typeId)
417 mImpl->CancelLoad(id, typeId);
420 bool ResourceLoader::IsLoading()
422 return mImpl->IsLoading();
425 void ResourceLoader::SetDpi(unsigned int dpiHor, unsigned int dpiVer)
430 bool ResourceLoader::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
432 DALI_LOG_TRACE_METHOD(gLoaderFilter);
434 DALI_ASSERT_DEBUG( 0 != filename.length());
439 buf.open(filename.c_str(), std::ios::in | std::ios::binary);
442 std::istream stream(&buf);
444 // determine data length
445 stream.seekg(0, std::ios_base::end);
446 unsigned int length = static_cast<unsigned int>( stream.tellg() );
447 stream.seekg(0, std::ios_base::beg);
450 buffer.resize(length);
451 // read data into buffer
452 stream.read(reinterpret_cast<char*>(buffer.data()), length);
454 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
460 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
467 std::string ResourceLoader::LoadFile(const std::string& filename) const
469 DALI_LOG_TRACE_METHOD(gLoaderFilter);
471 DALI_ASSERT_DEBUG( 0 != filename.length());
473 std::string contents;
476 buf.open(filename.c_str(), std::ios::in);
479 std::istream stream(&buf);
481 // determine data length
482 stream.seekg(0, std::ios_base::end);
483 unsigned int length = static_cast<unsigned int>( stream.tellg() );
484 stream.seekg(0, std::ios_base::beg);
487 contents.resize(length);
488 // read data into buffer
489 stream.read(&contents[0], length);
491 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
495 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
501 bool ResourceLoader::SaveFile(const std::string& filename, std::vector< unsigned char >& buffer)
503 DALI_LOG_TRACE_METHOD(gLoaderFilter);
505 DALI_ASSERT_DEBUG( 0 != filename.length());
510 buf.open(filename.c_str(), std::ios::out | std::ios_base::trunc | std::ios::binary);
513 std::ostream stream(&buf);
515 // determine size of buffer
516 int length = static_cast<int>(buffer.size());
518 // write contents of buffer to the file
519 stream.write(reinterpret_cast<char*>(buffer.data()), length);
523 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - wrote %d bytes\n", filename.c_str(), length);
528 #if defined(DEBUG_BUILD)
531 DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - failed to load\n", filename.c_str());
538 } // namespace TizenPlatform