2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/update/resources/resource-manager.h>
26 #include <dali/public-api/common/map-wrapper.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/public-api/images/image-attributes.h>
30 #include <dali/integration-api/glyph-set.h>
31 #include <dali/integration-api/debug.h>
33 #include <dali/internal/common/message.h>
35 #include <dali/internal/event/common/notification-manager.h>
36 #include <dali/internal/event/resources/resource-type-path.h>
37 #include <dali/internal/event/resources/resource-client.h>
38 #include <dali/internal/event/text/font-impl.h>
39 #include <dali/internal/event/text/atlas/atlas-size.h>
41 #include <dali/internal/update/modeling/scene-graph-mesh.h>
42 #include <dali/internal/update/common/discard-queue.h>
43 #include <dali/internal/update/resources/bitmap-metadata.h>
44 #include <dali/internal/update/resources/atlas-request-status.h>
45 #include <dali/internal/render/queue/render-queue.h>
47 #include <dali/internal/render/common/texture-cache-dispatcher.h>
48 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
51 using namespace Dali::Integration;
53 using Dali::Internal::SceneGraph::DiscardQueue;
54 using Dali::Internal::SceneGraph::RenderQueue;
55 using Dali::Internal::SceneGraph::TextureCacheDispatcher;
62 typedef set<ResourceId> LiveRequestContainer;
63 typedef LiveRequestContainer::iterator LiveRequestIter;
64 typedef LiveRequestContainer::size_type LiveRequestSize;
66 typedef map<ResourceId, ResourceTypeId> DeadRequestContainer;
67 typedef DeadRequestContainer::iterator DeadRequestIter;
68 typedef pair<ResourceId, ResourceTypeId> DeadRequestPair;
70 typedef vector<ResourceId> NotifyQueue;
71 typedef NotifyQueue::iterator NotifyQueueIter;
73 typedef map<ResourceId, BitmapMetadata> BitmapMetadataCache;
74 typedef BitmapMetadataCache::iterator BitmapMetadataIter;
75 typedef pair<ResourceId, BitmapMetadata> BitmapMetadataPair;
77 typedef map<ResourceId, ModelDataPtr> ModelCache;
78 typedef ModelCache::iterator ModelCacheIter;
79 typedef pair<ResourceId, ModelDataPtr> ModelDataPair;
81 typedef map<ResourceId, SceneGraph::Mesh*> MeshCache;
82 typedef MeshCache::iterator MeshCacheIter;
83 typedef pair<ResourceId, SceneGraph::Mesh*> MeshDataPair;
85 typedef map<ResourceId, ShaderDataPtr> ShaderCache;
86 typedef ShaderCache::iterator ShaderCacheIter;
87 typedef ShaderCache::size_type ShaderCacheSize;
88 typedef pair<ResourceId, ShaderDataPtr> ShaderDataPair;
90 struct ResourceManager::ResourceManagerImpl
92 ResourceManagerImpl( PlatformAbstraction& platformAbstraction,
93 NotificationManager& notificationManager,
94 SceneGraph::TextureCacheDispatcher& textureCacheDispatcher,
95 ResourcePostProcessList& resourcePostProcessQueue,
96 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
97 DiscardQueue& discardQueue,
98 RenderQueue& renderQueue )
99 : mPlatformAbstraction(platformAbstraction),
100 mNotificationManager(notificationManager),
101 mResourceClient(NULL),
102 mTextureCacheDispatcher(textureCacheDispatcher),
103 mResourcePostProcessQueue(resourcePostProcessQueue),
104 mPostProcessResourceDispatcher(postProcessResourceDispatcher),
105 mDiscardQueue(discardQueue),
106 mRenderQueue(renderQueue),
107 mNotificationCount(0)
111 ~ResourceManagerImpl()
113 // Cleanup existing meshes
114 for( MeshCacheIter it = mMeshes.begin();
122 PlatformAbstraction& mPlatformAbstraction;
123 NotificationManager& mNotificationManager;
124 ResourceClient* mResourceClient; // (needs to be a ptr - it's not instantiated yet)
125 TextureCacheDispatcher& mTextureCacheDispatcher;
126 ResourcePostProcessList& mResourcePostProcessQueue;
127 SceneGraph::PostProcessResourceDispatcher& mPostProcessResourceDispatcher;
128 DiscardQueue& mDiscardQueue; ///< Unwanted resources are added here during UpdateCache()
129 RenderQueue& mRenderQueue;
130 unsigned int mNotificationCount;
131 bool cacheUpdated; ///< returned by UpdateCache(). Set true in NotifyTickets to indicate a change in a resource
134 * These containers are used to processs requests, and ResourceCache callbacks.
135 * The live request containers are simply sets of integer resource ids.
136 * The ID of a new request will be placed in the loading container.
137 * If the Ticket is destroyed during the load, the ID will be removed.
138 * If the load fails, the ID will be moved to the failed container.
139 * When the Ticket is notified of the failure, the ID will be removed.
140 * If the load succeeds, the ID will be moved to the new-completed container.
141 * When the Ticket is notified of the completion, the ID will be moved to the old-completed container.
142 * If a Ticket is destroyed after a successful load, the ID will be moved to the dead container.
143 * When the resources are eventually deleted, the ID will be removed from the dead container.
145 LiveRequestContainer loadingRequests;
146 LiveRequestContainer newCompleteRequests;
147 LiveRequestContainer oldCompleteRequests;
148 LiveRequestContainer newFailedRequests;
149 LiveRequestContainer oldFailedRequests;
150 DeadRequestContainer deadRequests;
151 LiveRequestContainer saveRequests; ///< copy of id's being saved (must also be in newCompleteRequests or oldCompleteRequests)
152 LiveRequestContainer completeSaveRequests; ///< successful save ids are moved from saveRequests to here
154 AtlasRequestStatus atlasStatus; ///< load status of text atlases
157 * This is the resource cache. It's filled/emptied from within Core::Update()
159 BitmapMetadataCache mBitmapMetadata;
162 ShaderCache mShaders;
165 ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
166 NotificationManager& notificationManager,
167 TextureCacheDispatcher& textureCacheDispatcher,
168 ResourcePostProcessList& resourcePostProcessQueue,
169 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
170 DiscardQueue& discardQueue,
171 RenderQueue& renderQueue )
173 mImpl = new ResourceManagerImpl( platformAbstraction,
175 textureCacheDispatcher,
176 resourcePostProcessQueue,
177 postProcessResourceDispatcher,
182 ResourceManager::~ResourceManager()
187 /********************************************************************************
188 ************************ ResourceClient direct interface **********************
189 ********************************************************************************/
191 void ResourceManager::SetClient( ResourceClient& client )
193 mImpl->mResourceClient = &client;
196 /********************************************************************************
197 ************************ UpdateManager direct interface ***********************
198 ********************************************************************************/
200 bool ResourceManager::UpdateCache( BufferIndex updateBufferIndex )
202 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: UpdateCache(bufferIndex:%u)\n", updateBufferIndex);
204 // 1) Move unwanted resources to the DiscardQueue
206 DiscardDeadResources( updateBufferIndex );
208 // 2) Fill the resource cache
209 mImpl->cacheUpdated = false;
211 mImpl->mPlatformAbstraction.GetResources(*this);
213 return mImpl->cacheUpdated;
216 void ResourceManager::PostProcessResources( BufferIndex updateBufferIndex )
218 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
219 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: PostProcessResources()\n");
221 unsigned int numIds = mImpl->mResourcePostProcessQueue[ updateBufferIndex ].size();
224 // process the list where RenderManager put post process requests
225 for (i = 0; i < numIds; ++i)
227 ResourcePostProcessRequest ppRequest = mImpl->mResourcePostProcessQueue[ updateBufferIndex ][i];
228 switch(ppRequest.postProcess)
230 case ResourcePostProcessRequest::UPLOADED:
231 SendToClient( UploadedMessage( *mImpl->mResourceClient, ppRequest.id ) );
233 case ResourcePostProcessRequest::SAVE:
234 SendToClient( SaveResourceMessage( *mImpl->mResourceClient, ppRequest.id ) );
236 case ResourcePostProcessRequest::DELETED:
237 // TextureObservers handled in TextureCache
242 mImpl->mResourcePostProcessQueue[ updateBufferIndex ].clear();
246 /********************************************************************************
247 *************************** CoreImpl direct interface *************************
248 ********************************************************************************/
250 bool ResourceManager::ResourcesToProcess()
252 bool workTodo = false;
254 // need to make sure we have passed all the notifications to the event handling side
255 workTodo |= !mImpl->newCompleteRequests.empty();
256 workTodo |= !mImpl->newFailedRequests.empty();
257 // check if there's something still loading
258 workTodo |= !mImpl->loadingRequests.empty();
259 workTodo |= !mImpl->saveRequests.empty();
265 /********************************************************************************
266 ********************************* Message handlers *****************************
267 ********************************************************************************/
269 void ResourceManager::HandleLoadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
271 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadResourceRequest(id:%u, path:%s, type.id:%d)\n", id, typePath.path.c_str(), typePath.type->id);
273 // Add ID to the loading set
274 mImpl->loadingRequests.insert(id);
276 // Update atlas status if this request is a text request
277 mImpl->atlasStatus.CheckAndSaveTextRequest(id, typePath);
279 ClearRequestedGlyphArea(id, typePath);
281 // Make the load request last
282 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
285 void ResourceManager::HandleDecodeResourceRequest(
287 const ResourceTypePath& typePath,
288 RequestBufferPtr buffer,
289 Integration::LoadResourcePriority priority )
291 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleDecodeResourceRequest(id:%u, buffer.size:%u, type.id:%u)\n", id, buffer->GetVector().Size(), typePath.type->id);
293 // We would update atlas status and clear the glyph area if text were supported and this request was a text request:
294 if( typePath.type->id == ResourceText )
296 DALI_LOG_WARNING("Decoding from memory buffers not supported for Text resources.");
300 // Add ID to the loading set
301 mImpl->loadingRequests.insert(id);
303 // Make the load request, stuffing the buffer of encoded bytes into the same field used when saving resources:
304 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, "", buffer, priority));
307 void ResourceManager::HandleAddBitmapImageRequest( ResourceId id, Bitmap* bitmap )
309 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
310 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddBitmapImageRequest(id:%u)\n", id);
312 mImpl->oldCompleteRequests.insert(id);
313 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
314 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
317 void ResourceManager::HandleAddNativeImageRequest(ResourceId id, NativeImagePtr nativeImage)
319 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
320 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddNativeImageRequest(id:%u)\n", id);
322 mImpl->oldCompleteRequests.insert(id);
324 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImage)));
325 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImage );
328 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
330 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
331 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
333 mImpl->oldCompleteRequests.insert(id);
335 BitmapMetadata bitmapMetadata = BitmapMetadata::New(width, height, pixelFormat);
336 bitmapMetadata.SetIsFramebuffer(true);
337 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
339 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, width, height, pixelFormat );
342 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, NativeImagePtr nativeImage )
344 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
345 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
347 mImpl->oldCompleteRequests.insert(id);
349 BitmapMetadata bitmapMetadata = BitmapMetadata::New(nativeImage->GetWidth(), nativeImage->GetHeight(), nativeImage->GetPixelFormat());
350 bitmapMetadata.SetIsNativeImage(true);
351 bitmapMetadata.SetIsFramebuffer(true);
352 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
354 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, nativeImage );
357 void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
359 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateTextureRequest(id:%u)\n", id);
361 mImpl->oldCompleteRequests.insert(id);
362 mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ );
365 void ResourceManager::HandleUpdateTextureRequest( ResourceId id, const BitmapUploadArray& uploadArray )
367 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( id, uploadArray );
370 void ResourceManager::HandleAllocateMeshRequest( ResourceId id, MeshData* meshData )
372 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateMeshRequest(id:%u)\n", id);
374 SceneGraph::Mesh* renderableMesh(SceneGraph::Mesh::New(id, mImpl->mPostProcessResourceDispatcher, meshData));
376 DALI_ASSERT_ALWAYS(renderableMesh && "renderableMesh not created");
378 // Add the ID to the completed set, and store the resource
379 mImpl->newCompleteRequests.insert(id);
380 mImpl->mMeshes.insert(MeshDataPair(id, renderableMesh));
382 // Let NotificationManager know that the resource manager needs to do some processing
386 void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath )
388 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
390 const ShaderResourceType* shaderType = dynamic_cast<const ShaderResourceType*>(typePath.type);
391 DALI_ASSERT_DEBUG(shaderType);
395 ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader));
397 // For startup speed, shader file load must be synchronous in this
398 // thread - Update manager will get a message following this to use
399 // the program data immediately. (i.e. if this load fails, then
402 // It would be safer, though slower, to handle shader binary load
403 // failure in the event thread through the ticket mechanism;
404 // however, as we are not using the result in the ShaderFactory, it
405 // is safe to return LoadSuccess even if the load failed. Ignore the
407 mImpl->mPlatformAbstraction.LoadFile(typePath.path, shaderData->buffer);
409 // Add the ID to the completed set
410 mImpl->newCompleteRequests.insert(id);
412 // Cache the resource
413 mImpl->mShaders.insert(ShaderDataPair(id, shaderData));
415 // Let NotificationManager know that the resource manager needs to do some processing
420 void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area )
424 mImpl->mTextureCacheDispatcher.DispatchUpdateTextureArea( textureId, area );
428 void ResourceManager::HandleUpdateMeshRequest( BufferIndex updateBufferIndex, ResourceId id, MeshData* meshData )
430 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
431 SceneGraph::Mesh* mesh = GetMesh( id );
432 DALI_ASSERT_DEBUG(mesh);
434 // Update the mesh data
435 mesh->SetMeshData( meshData );
437 // Update the GL buffers in the next Render
438 typedef MessageDoubleBuffered2< SceneGraph::Mesh, SceneGraph::Mesh::ThreadBuffer, OwnerPointer<MeshData> > DerivedType;
440 // Reserve some memory inside the render queue
441 unsigned int* slot = mImpl->mRenderQueue.ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
443 // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
444 new (slot) DerivedType( mesh, &SceneGraph::Mesh::MeshDataUpdated, SceneGraph::Mesh::RENDER_THREAD, meshData );
447 void ResourceManager::HandleReloadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
449 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
450 DALI_LOG_INFO( Debug::Filter::gResource, Debug::General, "ResourceManager: HandleReloadRequest(id:%u, path:%s)\n", id, typePath.path.c_str() );
452 bool resourceIsAlreadyLoading = true;
454 // ID might be in the loading set
455 LiveRequestIter iter = mImpl->loadingRequests.find( id );
456 if ( iter == mImpl->loadingRequests.end() )
458 // Add ID to the loading set
459 mImpl->loadingRequests.insert(id);
460 resourceIsAlreadyLoading = false;
463 if ( !resourceIsAlreadyLoading )
465 //load resource again
466 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
467 SendToClient( LoadingMessage( *mImpl->mResourceClient, id ) );
471 void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTypePath& typePath )
473 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleSaveResourceRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
475 bool resourceFound = false;
477 // ID must be in the complete sets
478 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
479 if (iter != mImpl->newCompleteRequests.end())
481 resourceFound = true;
485 LiveRequestIter iter = mImpl->oldCompleteRequests.find(id);
486 if (iter != mImpl->oldCompleteRequests.end())
488 resourceFound = true;
494 ResourcePointer resource;
495 DALI_ASSERT_DEBUG( typePath.type != NULL );
497 switch( typePath.type->id )
503 case ResourceNativeImage:
507 case ResourceTargetImage:
513 resource = GetShaderData(id);
518 resource = GetModelData(id);
531 if( resource ) // i.e. if it's a saveable resource
533 mImpl->saveRequests.insert(id);
535 ResourceRequest request(id, *typePath.type, typePath.path, resource);
536 mImpl->mPlatformAbstraction.SaveResource(request);
541 static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
543 return container.erase(id) != 0;
546 void ResourceManager::HandleDiscardResourceRequest( ResourceId deadId, ResourceTypeId typeId )
548 bool wasComplete = false;
549 bool wasLoading = false;
551 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleDiscardResourceRequest(id:%u)\n", deadId);
553 // remove copies of the deadId from completed/failed saving sets
554 RemoveId(mImpl->completeSaveRequests, deadId);
556 // Search for the ID in one of the live containers
557 // IDs are only briefly held in the new-completed or failed containers; check those last
558 bool foundLiveRequest = false;
560 // Try removing from the old-completed requests
561 foundLiveRequest = wasComplete = RemoveId(mImpl->oldCompleteRequests, deadId);
563 // Try removing from the loading requests
564 if (!foundLiveRequest)
566 foundLiveRequest = wasLoading = RemoveId(mImpl->loadingRequests, deadId);
569 // Try removing from the new completed requests
570 if (!foundLiveRequest)
572 foundLiveRequest = wasComplete = RemoveId(mImpl->newCompleteRequests, deadId);
575 // Try removing from the new failed requests
576 if (!foundLiveRequest)
578 foundLiveRequest = RemoveId(mImpl->newFailedRequests, deadId);
581 // Try removing from the old failed requests
582 if (!foundLiveRequest)
584 foundLiveRequest = RemoveId(mImpl->oldFailedRequests, deadId);
587 // ID should be in one of the live sets
588 if (!foundLiveRequest)
590 DALI_LOG_WARNING("HandleDiscardResourceRequest: ID should be in one of the live sets!\n");
592 DALI_ASSERT_DEBUG(foundLiveRequest);
596 if(typeId == ResourceBitmap ||
597 typeId == ResourceNativeImage ||
598 typeId == ResourceTargetImage )
600 // remove the meta data
601 mImpl->mBitmapMetadata.erase( deadId );
603 // destroy the texture
604 mImpl->mTextureCacheDispatcher.DispatchDiscardTexture( deadId );
608 // Move ID from completed to dead set
609 mImpl->deadRequests.insert(DeadRequestPair(deadId, typeId));
615 mImpl->mPlatformAbstraction.CancelLoad(deadId, typeId);
619 void ResourceManager::HandleAtlasUpdateRequest( ResourceId id, ResourceId atlasId, LoadStatus loadStatus )
621 mImpl->atlasStatus.Update(id, atlasId, loadStatus );
624 /********************************************************************************
625 ******************** Event thread object direct interface *********************
626 ********************************************************************************/
628 ModelDataPtr ResourceManager::GetModelData(ResourceId id)
630 ModelDataPtr modelData;
631 ModelCacheIter iter = mImpl->mModels.find(id);
632 if(iter != mImpl->mModels.end())
634 modelData = iter->second;
639 /********************************************************************************
640 ******************** Update thread object direct interface ********************
641 ********************************************************************************/
643 bool ResourceManager::IsResourceLoaded(ResourceId id)
649 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
650 if( iter != mImpl->newCompleteRequests.end() )
656 iter = mImpl->oldCompleteRequests.find(id);
657 if( iter != mImpl->oldCompleteRequests.end() )
667 bool ResourceManager::IsResourceLoadFailed(ResourceId id)
669 bool loadFailed = false;
673 LiveRequestIter iter = mImpl->newFailedRequests.find(id);
674 if( iter != mImpl->newFailedRequests.end() )
680 iter = mImpl->oldFailedRequests.find(id);
681 if( iter != mImpl->oldFailedRequests.end() )
691 BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id)
693 BitmapMetadata metadata;
697 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
698 if( iter != mImpl->mBitmapMetadata.end() )
700 metadata = iter->second;
707 Internal::SceneGraph::Mesh* ResourceManager::GetMesh(ResourceId id)
709 SceneGraph::Mesh* mesh = NULL;
710 MeshCacheIter iter = mImpl->mMeshes.find(id);
712 if (iter != mImpl->mMeshes.end())
720 ShaderDataPtr ResourceManager::GetShaderData(ResourceId id)
722 ShaderDataPtr shaderData;
723 ShaderCacheIter iter = mImpl->mShaders.find(id);
724 if(iter != mImpl->mShaders.end())
726 shaderData = iter->second;
731 bool ResourceManager::IsAtlasLoaded(ResourceId id)
733 return mImpl->atlasStatus.IsLoadComplete(id);
736 LoadStatus ResourceManager::GetAtlasLoadStatus( ResourceId atlasId )
738 return mImpl->atlasStatus.GetLoadStatus( atlasId );
741 /********************************************************************************
742 ************************* ResourceCache Implementation ************************
743 ********************************************************************************/
745 void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, ResourcePointer resource, LoadStatus loadStatus )
747 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
748 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: LoadResponse(id:%u, status=%s)\n", id, loadStatus==RESOURCE_LOADING?"LOADING":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE");
750 // ID might be in the loading set
751 LiveRequestIter iter = mImpl->loadingRequests.find(id);
753 if ( iter != mImpl->loadingRequests.end() )
755 if( loadStatus == RESOURCE_COMPLETELY_LOADED )
757 // Remove from the loading set
758 mImpl->loadingRequests.erase(iter);
760 // Add the ID to the new-completed set, and store the resource
761 mImpl->newCompleteRequests.insert(id);
768 DALI_ASSERT_DEBUG( loadStatus == RESOURCE_COMPLETELY_LOADED && "Partial results not handled for image loading.\n" );
769 Bitmap* const bitmap = static_cast<Bitmap*>( resource.Get() );
772 DALI_LOG_ERROR( "Missing bitmap in loaded resource with id %u.\n", id );
775 unsigned int bitmapWidth = bitmap->GetImageWidth();
776 unsigned int bitmapHeight = bitmap->GetImageHeight();
778 if( Bitmap::PackedPixelsProfile * packedBitmap = bitmap->GetPackedPixelsProfile() )
780 bitmapWidth = packedBitmap->GetBufferWidth();
781 bitmapHeight = packedBitmap->GetBufferHeight();
783 Pixel::Format pixelFormat = bitmap->GetPixelFormat();
785 ImageAttributes attrs = ImageAttributes::New( bitmapWidth, bitmapHeight, pixelFormat ); ///!< Issue #AHC01
786 UpdateImageTicket (id, attrs);
788 // Check for reloaded bitmap
789 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
790 if (iter != mImpl->mBitmapMetadata.end())
792 iter->second.Update(bitmap);
793 mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( id, bitmap );
797 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
798 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
804 case ResourceNativeImage:
806 NativeImagePtr nativeImg( static_cast<NativeImage*>(resource.Get()) );
808 ImageAttributes attrs = ImageAttributes::New(nativeImg->GetWidth(), nativeImg->GetHeight(), nativeImg->GetPixelFormat());
810 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImg)));
811 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImg );
813 UpdateImageTicket (id, attrs);
817 case ResourceTargetImage:
824 mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
830 mImpl->mModels.insert(ModelDataPair(id, static_cast<ModelData*>(resource.Get())));
841 /* here we return a vector of Characters (glyph data + bitmap)*/
842 GlyphSetPointer glyphSet = static_cast<GlyphSet*>(resource.Get());
843 DALI_ASSERT_DEBUG( glyphSet );
844 UploadGlyphsToTexture(*glyphSet);
845 mImpl->atlasStatus.Update(id, glyphSet->GetAtlasResourceId(), loadStatus );
846 SendToClient( LoadingGlyphSetSucceededMessage( *mImpl->mResourceClient, id, glyphSet, loadStatus) );
851 // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
854 // flag that a load has completed and the cache updated
855 mImpl->cacheUpdated = true;
859 DALI_LOG_ERROR("ResourceManager::LoadResponse() received a stray load notification for a resource whose loading is not being tracked: (id:%u, status=%s)\n", id, loadStatus==RESOURCE_LOADING?"LOADING":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE");
863 void ResourceManager::SaveComplete(ResourceId id, ResourceTypeId type)
865 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
866 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveComplete(id:%u)\n", id);
868 // ID must be in the saving set
869 LiveRequestIter iter = mImpl->saveRequests.find(id);
871 if (iter != mImpl->saveRequests.end())
873 // Remove from the saving set
874 mImpl->saveRequests.erase(iter);
876 // If resource has not been discarded..
877 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
879 SendToClient( SavingSucceededMessage( *mImpl->mResourceClient, id ) );
882 // clear the uneeded binary shader data
883 if( type == ResourceShader )
885 ShaderCacheIter shaderIter = mImpl->mShaders.find(id);
886 DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
887 ShaderDataPtr shaderDataPtr = shaderIter->second;
888 std::vector<unsigned char>().swap(shaderDataPtr->buffer);
893 void ResourceManager::LoadFailed(ResourceId id, ResourceFailure failure)
895 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: LoadFailed(id:%u)\n", id);
897 // ID might be in the loading set
898 LiveRequestIter iter = mImpl->loadingRequests.find(id);
900 if (iter != mImpl->loadingRequests.end())
902 // Remove from the loading set
903 mImpl->loadingRequests.erase(iter);
905 // Add the ID to the failed set, this will trigger a notification during UpdateTickets
906 mImpl->newFailedRequests.insert(id);
908 // Let NotificationManager know that the resource manager needs to do some processing
913 void ResourceManager::SaveFailed(ResourceId id, ResourceFailure failure)
915 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
916 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveFailed(id:%u)\n", id);
918 // ID must be in the saving set
919 LiveRequestIter iter = mImpl->saveRequests.find(id);
921 if (iter != mImpl->saveRequests.end())
923 // Remove from the saving set
924 mImpl->saveRequests.erase(iter);
926 // If resource has not been discarded..
928 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
930 SendToClient( SavingFailedMessage( *mImpl->mResourceClient, id ) );
935 /********************************************************************************
936 ********************************* Private Methods *****************************
937 ********************************************************************************/
939 void ResourceManager::ClearRequestedGlyphArea( ResourceId id, const ResourceTypePath& typePath )
941 if( typePath.type->id == ResourceText )
943 const TextResourceType *textResourceType = static_cast<const TextResourceType*>(typePath.type);
944 ResourceId atlasId = textResourceType->mTextureAtlasId;
946 BitmapClearArray clearAreas;
948 float blockSize = GlyphAtlasSize::GetBlockSize();
949 // Get x, y from each character:
950 for( TextResourceType::CharacterList::const_iterator iter = textResourceType->mCharacterList.begin(),
951 end = textResourceType->mCharacterList.end() ;
952 iter != end ; iter ++ )
955 clearArea.x= iter->xPosition;
956 clearArea.y= iter->yPosition;
957 clearAreas.push_back(clearArea);
960 mImpl->mTextureCacheDispatcher.DispatchClearAreas( atlasId, clearAreas, blockSize, 0x00 );
964 void ResourceManager::UploadGlyphsToTexture( const GlyphSet& glyphSet )
966 // the glyphset contains an array of bitmap / characters .
967 // This function uploads the bitmaps to the associated texture atlas
969 const GlyphSet::CharacterList& charList( glyphSet.GetCharacterList() );
970 BitmapUploadArray uploadArray;
972 for(std::size_t i = 0, count = charList.size() ; i < count; i++ )
974 const GlyphSet::Character& character( charList[i] );
976 // grab a pointer to the bitmap
977 Bitmap* bitmap( character.first.Get() );
979 // create a bitmap upload object, then add it to the array
980 BitmapUpload upload( bitmap->ReleaseBuffer(), // Inform the bitmap we're taking ownership of it's pixel buffer.
981 character.second.xPosition, // x position in the texture to which upload the bitmap
982 character.second.yPosition, // y position in the texture to which upload the bitmap
983 bitmap->GetImageWidth(), // bitmap width
984 bitmap->GetImageHeight(), // bitmap height
985 BitmapUpload::DISCARD_PIXEL_DATA ); // tell the the texture to delete the bitmap pixel buffer when it's done
987 uploadArray.push_back( upload );
990 ResourceId textureId = glyphSet.GetAtlasResourceId();
991 if( IsResourceLoaded( textureId ) )
993 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( textureId, uploadArray );
998 void ResourceManager::NotifyTickets()
1000 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1001 // Success notifications
1002 for (LiveRequestIter iter = mImpl->newCompleteRequests.begin(); iter != mImpl->newCompleteRequests.end(); ++iter)
1004 // Move to oldCompleteRequests
1005 mImpl->oldCompleteRequests.insert(*iter);
1007 SendToClient( LoadingSucceededMessage( *mImpl->mResourceClient, *iter ) );
1009 mImpl->newCompleteRequests.clear();
1011 // Failure notifications
1012 for (LiveRequestIter iter = mImpl->newFailedRequests.begin(); iter != mImpl->newFailedRequests.end(); ++iter)
1014 // Move to oldFailedRequests
1015 mImpl->oldFailedRequests.insert(*iter);
1017 // We should have a matching request ticket
1018 SendToClient( LoadingFailedMessage( *mImpl->mResourceClient, *iter ) );
1020 mImpl->newFailedRequests.clear();
1023 void ResourceManager::UpdateImageTicket( ResourceId id, ImageAttributes& attributes ) ///!< Issue #AHC01
1025 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1026 // ResourceLoader should load images considering the requested size
1027 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: UpdateImageTicket(id:%u)\n", id);
1029 // Let NotificationManager know that the resource manager needs to do some processing
1030 SendToClient( UpdateImageTicketMessage( *mImpl->mResourceClient, id, attributes) );
1033 void ResourceManager::SendToClient( MessageBase* message )
1035 mImpl->mNotificationManager.QueueMessage( message );
1038 void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex )
1040 for (DeadRequestIter iter = mImpl->deadRequests.begin(); iter != mImpl->deadRequests.end(); )
1042 // Delay destroying ids in saveRequests
1043 if( mImpl->saveRequests.find(iter->first) != mImpl->saveRequests.end())
1050 * We should find a resource of the correct type, and move it to the DiscardQueue.
1052 switch (iter->second)
1054 case ResourceBitmap:
1055 case ResourceNativeImage:
1056 case ResourceTargetImage:
1061 ModelCacheIter model = mImpl->mModels.find(iter->first);
1062 DALI_ASSERT_DEBUG( mImpl->mModels.end() != model );
1064 mImpl->mDiscardQueue.Add( updateBufferIndex, *(model->second) );
1065 mImpl->mModels.erase( model );
1071 MeshCacheIter mesh = mImpl->mMeshes.find(iter->first);
1072 DALI_ASSERT_DEBUG( mImpl->mMeshes.end() != mesh );
1074 mImpl->mDiscardQueue.Add( updateBufferIndex, mesh->second );
1075 mImpl->mMeshes.erase( mesh );
1084 case ResourceShader:
1086 ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first);
1087 DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
1089 mImpl->mDiscardQueue.Add( updateBufferIndex, *(shaderIter->second) );
1090 mImpl->mShaders.erase( shaderIter );
1095 mImpl->atlasStatus.Remove(iter->first);
1097 // Erase the item and increment the iterator
1098 mImpl->deadRequests.erase(iter++);
1102 } // namespace Internal