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 <dali/internal/update/resources/resource-manager.h>
26 #include <dali/public-api/common/map-wrapper.h>
27 #include <dali/public-api/common/set-wrapper.h>
28 #include <dali/public-api/math/vector2.h>
29 #include <dali/public-api/images/image-attributes.h>
31 #include <dali/integration-api/glyph-set.h>
32 #include <dali/integration-api/debug.h>
34 #include <dali/internal/common/message.h>
36 #include <dali/internal/event/common/notification-manager.h>
37 #include <dali/internal/event/resources/resource-type-path.h>
38 #include <dali/internal/event/resources/resource-client.h>
39 #include <dali/internal/event/text/font-impl.h>
40 #include <dali/internal/event/text/atlas/atlas-size.h>
42 #include <dali/internal/update/modeling/scene-graph-mesh.h>
43 #include <dali/internal/update/common/discard-queue.h>
44 #include <dali/internal/update/resources/bitmap-metadata.h>
45 #include <dali/internal/update/resources/atlas-request-status.h>
46 #include <dali/internal/render/queue/render-queue.h>
48 #include <dali/internal/render/common/texture-cache-dispatcher.h>
49 #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 std::set<ResourceId> LiveRequestContainer;
63 typedef LiveRequestContainer::iterator LiveRequestIter;
64 typedef LiveRequestContainer::size_type LiveRequestSize;
66 typedef std::map<ResourceId, ResourceTypeId> DeadRequestContainer;
67 typedef DeadRequestContainer::iterator DeadRequestIter;
68 typedef std::pair<ResourceId, ResourceTypeId> DeadRequestPair;
70 typedef std::vector<ResourceId> NotifyQueue;
71 typedef NotifyQueue::iterator NotifyQueueIter;
73 typedef std::map<ResourceId, BitmapMetadata> BitmapMetadataCache;
74 typedef BitmapMetadataCache::iterator BitmapMetadataIter;
75 typedef std::pair<ResourceId, BitmapMetadata> BitmapMetadataPair;
77 typedef std::map<ResourceId, ModelDataPtr> ModelCache;
78 typedef ModelCache::iterator ModelCacheIter;
79 typedef std::pair<ResourceId, ModelDataPtr> ModelDataPair;
81 typedef std::map<ResourceId, SceneGraph::Mesh*> MeshCache;
82 typedef MeshCache::iterator MeshCacheIter;
83 typedef std::pair<ResourceId, SceneGraph::Mesh*> MeshDataPair;
85 typedef std::map<ResourceId, ShaderDataPtr> ShaderCache;
86 typedef ShaderCache::iterator ShaderCacheIter;
87 typedef ShaderCache::size_type ShaderCacheSize;
88 typedef std::pair<ResourceId, ShaderDataPtr> ShaderDataPair;
90 static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
92 return container.erase(id) != 0;
95 struct ResourceManager::ResourceManagerImpl
97 ResourceManagerImpl( PlatformAbstraction& platformAbstraction,
98 NotificationManager& notificationManager,
99 SceneGraph::TextureCacheDispatcher& textureCacheDispatcher,
100 ResourcePostProcessList& resourcePostProcessQueue,
101 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
102 DiscardQueue& discardQueue,
103 RenderQueue& renderQueue )
104 : mPlatformAbstraction(platformAbstraction),
105 mNotificationManager(notificationManager),
106 mResourceClient(NULL),
107 mTextureCacheDispatcher(textureCacheDispatcher),
108 mResourcePostProcessQueue(resourcePostProcessQueue),
109 mPostProcessResourceDispatcher(postProcessResourceDispatcher),
110 mDiscardQueue(discardQueue),
111 mRenderQueue(renderQueue),
112 mNotificationCount(0),
117 ~ResourceManagerImpl()
119 // Cleanup existing meshes
120 for( MeshCacheIter it = mMeshes.begin();
128 PlatformAbstraction& mPlatformAbstraction;
129 NotificationManager& mNotificationManager;
130 ResourceClient* mResourceClient; // (needs to be a ptr - it's not instantiated yet)
131 TextureCacheDispatcher& mTextureCacheDispatcher;
132 ResourcePostProcessList& mResourcePostProcessQueue;
133 SceneGraph::PostProcessResourceDispatcher& mPostProcessResourceDispatcher;
134 DiscardQueue& mDiscardQueue; ///< Unwanted resources are added here during UpdateCache()
135 RenderQueue& mRenderQueue;
136 unsigned int mNotificationCount;
137 bool cacheUpdated; ///< returned by UpdateCache(). Set true in NotifyTickets to indicate a change in a resource
140 * These containers are used to processs requests, and ResourceCache callbacks.
141 * The live request containers are simply sets of integer resource ids.
142 * The ID of a new request will be placed in the loading container.
143 * If the Ticket is destroyed during the load, the ID will be removed.
144 * If the load fails, the ID will be moved to the failed container.
145 * When the Ticket is notified of the failure, the ID will be removed.
146 * If the load succeeds, the ID will be moved to the new-completed container.
147 * When the Ticket is notified of the completion, the ID will be moved to the old-completed container.
148 * If a Ticket is destroyed after a successful load, the ID will be moved to the dead container.
149 * When the resources are eventually deleted, the ID will be removed from the dead container.
151 LiveRequestContainer loadingRequests;
152 LiveRequestContainer newCompleteRequests;
153 LiveRequestContainer oldCompleteRequests;
154 LiveRequestContainer newFailedRequests;
155 LiveRequestContainer oldFailedRequests;
156 DeadRequestContainer deadRequests;
157 LiveRequestContainer saveRequests; ///< copy of id's being saved (must also be in newCompleteRequests or oldCompleteRequests)
158 LiveRequestContainer completeSaveRequests; ///< successful save ids are moved from saveRequests to here
160 AtlasRequestStatus atlasStatus; ///< load status of text atlases
163 * This is the resource cache. It's filled/emptied from within Core::Update()
165 BitmapMetadataCache mBitmapMetadata;
168 ShaderCache mShaders;
171 ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
172 NotificationManager& notificationManager,
173 TextureCacheDispatcher& textureCacheDispatcher,
174 ResourcePostProcessList& resourcePostProcessQueue,
175 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
176 DiscardQueue& discardQueue,
177 RenderQueue& renderQueue )
179 mImpl = new ResourceManagerImpl( platformAbstraction,
181 textureCacheDispatcher,
182 resourcePostProcessQueue,
183 postProcessResourceDispatcher,
188 ResourceManager::~ResourceManager()
193 /********************************************************************************
194 ************************ ResourceClient direct interface **********************
195 ********************************************************************************/
197 void ResourceManager::SetClient( ResourceClient& client )
199 mImpl->mResourceClient = &client;
202 /********************************************************************************
203 ************************ UpdateManager direct interface ***********************
204 ********************************************************************************/
206 bool ResourceManager::UpdateCache( BufferIndex updateBufferIndex )
208 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: UpdateCache(bufferIndex:%u)\n", updateBufferIndex);
210 // 1) Move unwanted resources to the DiscardQueue
212 DiscardDeadResources( updateBufferIndex );
214 // 2) Fill the resource cache
215 mImpl->cacheUpdated = false;
217 mImpl->mPlatformAbstraction.GetResources(*this);
219 return mImpl->cacheUpdated;
222 void ResourceManager::PostProcessResources( BufferIndex updateBufferIndex )
224 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
225 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: PostProcessResources()\n");
227 unsigned int numIds = mImpl->mResourcePostProcessQueue[ updateBufferIndex ].size();
230 // process the list where RenderManager put post process requests
231 for (i = 0; i < numIds; ++i)
233 ResourcePostProcessRequest ppRequest = mImpl->mResourcePostProcessQueue[ updateBufferIndex ][i];
234 switch(ppRequest.postProcess)
236 case ResourcePostProcessRequest::UPLOADED:
238 SendToClient( UploadedMessage( *mImpl->mResourceClient, ppRequest.id ) );
241 case ResourcePostProcessRequest::SAVE:
243 SendToClient( SaveResourceMessage( *mImpl->mResourceClient, ppRequest.id ) );
247 case ResourcePostProcessRequest::DELETED:
249 // TextureObservers handled in TextureCache
255 mImpl->mResourcePostProcessQueue[ updateBufferIndex ].clear();
259 /********************************************************************************
260 *************************** CoreImpl direct interface *************************
261 ********************************************************************************/
263 bool ResourceManager::ResourcesToProcess()
265 bool workTodo = false;
267 // need to make sure we have passed all the notifications to the event handling side
268 workTodo |= !mImpl->newCompleteRequests.empty();
269 workTodo |= !mImpl->newFailedRequests.empty();
270 // check if there's something still loading
271 workTodo |= !mImpl->loadingRequests.empty();
272 workTodo |= !mImpl->saveRequests.empty();
278 /********************************************************************************
279 ********************************* Message handlers *****************************
280 ********************************************************************************/
282 void ResourceManager::HandleLoadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
284 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);
286 // Add ID to the loading set
287 mImpl->loadingRequests.insert(id);
289 // Update atlas status if this request is a text request
290 mImpl->atlasStatus.CheckAndSaveTextRequest(id, typePath);
292 ClearRequestedGlyphArea(id, typePath);
294 // Make the load request last
295 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
298 void ResourceManager::HandleDecodeResourceRequest(
300 const ResourceTypePath& typePath,
301 RequestBufferPtr buffer,
302 Integration::LoadResourcePriority priority )
304 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);
306 // We would update atlas status and clear the glyph area if text were supported and this request was a text request:
307 if( typePath.type->id == ResourceText )
309 DALI_LOG_WARNING("Decoding from memory buffers not supported for Text resources.");
313 // Add ID to the loading set
314 mImpl->loadingRequests.insert(id);
316 // Make the load request, stuffing the buffer of encoded bytes into the same field used when saving resources:
317 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, "", buffer, priority));
320 void ResourceManager::HandleAddBitmapImageRequest( ResourceId id, BitmapPtr bitmap )
322 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
323 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddBitmapImageRequest(id:%u)\n", id);
325 mImpl->oldCompleteRequests.insert(id);
326 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New( bitmap.Get() )));
327 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap.Get() );
330 void ResourceManager::HandleAddNativeImageRequest(ResourceId id, NativeImagePtr nativeImage)
332 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
333 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddNativeImageRequest(id:%u)\n", id);
335 mImpl->oldCompleteRequests.insert(id);
337 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImage)));
338 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImage );
341 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
343 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
344 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
346 mImpl->oldCompleteRequests.insert(id);
348 BitmapMetadata bitmapMetadata = BitmapMetadata::New(width, height, pixelFormat);
349 bitmapMetadata.SetIsFramebuffer(true);
350 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
352 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, width, height, pixelFormat );
355 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, NativeImagePtr nativeImage )
357 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
358 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
360 mImpl->oldCompleteRequests.insert(id);
362 BitmapMetadata bitmapMetadata = BitmapMetadata::New(nativeImage->GetWidth(), nativeImage->GetHeight(), nativeImage->GetPixelFormat());
363 bitmapMetadata.SetIsNativeImage(true);
364 bitmapMetadata.SetIsFramebuffer(true);
365 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
367 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, nativeImage );
370 void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
372 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateTextureRequest(id:%u)\n", id);
374 mImpl->oldCompleteRequests.insert(id);
375 mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ );
378 void ResourceManager::HandleUpdateTextureRequest( ResourceId id, const BitmapUploadArray& uploadArray )
380 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( id, uploadArray );
383 void ResourceManager::HandleAllocateMeshRequest( ResourceId id, MeshData* meshData )
385 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateMeshRequest(id:%u)\n", id);
387 SceneGraph::Mesh* renderableMesh(SceneGraph::Mesh::New(id, mImpl->mPostProcessResourceDispatcher, mImpl->mRenderQueue, meshData));
389 DALI_ASSERT_ALWAYS(renderableMesh && "renderableMesh not created");
391 // Add the ID to the completed set, and store the resource
392 mImpl->newCompleteRequests.insert(id);
393 mImpl->mMeshes.insert(MeshDataPair(id, renderableMesh));
395 // Let NotificationManager know that the resource manager needs to do some processing
399 void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath )
401 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
403 const ShaderResourceType* shaderType = dynamic_cast<const ShaderResourceType*>(typePath.type);
404 DALI_ASSERT_DEBUG(shaderType);
408 ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader));
410 mImpl->mPlatformAbstraction.LoadFile(typePath.path, shaderData->GetBuffer());
412 // Add the ID to the completed set
413 mImpl->newCompleteRequests.insert(id);
415 // Cache the resource
416 mImpl->mShaders.insert(ShaderDataPair(id, shaderData));
418 // Let NotificationManager know that the resource manager needs to do some processing
423 void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area )
427 mImpl->mTextureCacheDispatcher.DispatchUpdateTextureArea( textureId, area );
431 void ResourceManager::HandleUploadBitmapRequest( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
433 if( destId && srcId )
435 mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( destId, srcId, xOffset, yOffset );
439 void ResourceManager::HandleUpdateMeshRequest( BufferIndex updateBufferIndex, ResourceId id, MeshData* meshData )
441 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
442 SceneGraph::Mesh* mesh = GetMesh( id );
443 DALI_ASSERT_DEBUG(mesh);
445 // Update the mesh data
446 mesh->SetMeshData( meshData );
448 // Update the GL buffers in the next Render
449 typedef MessageDoubleBuffered2< SceneGraph::Mesh, SceneGraph::Mesh::ThreadBuffer, OwnerPointer<MeshData> > DerivedType;
451 // Reserve some memory inside the render queue
452 unsigned int* slot = mImpl->mRenderQueue.ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
454 // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
455 new (slot) DerivedType( mesh, &SceneGraph::Mesh::MeshDataUpdated, SceneGraph::Mesh::RENDER_THREAD, meshData );
458 void ResourceManager::HandleReloadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority, bool resetFinishedStatus )
460 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
461 DALI_LOG_INFO( Debug::Filter::gResource, Debug::General, "ResourceManager: HandleReloadRequest(id:%u, path:%s)\n", id, typePath.path.c_str() );
463 bool resourceIsAlreadyLoading = true;
465 if( resetFinishedStatus )
467 if( ! RemoveId( mImpl->newCompleteRequests, id ) )
469 RemoveId( mImpl->oldCompleteRequests, id );
473 // ID might be in the loading set
474 LiveRequestIter iter = mImpl->loadingRequests.find( id );
475 if ( iter == mImpl->loadingRequests.end() )
477 // Add ID to the loading set
478 mImpl->loadingRequests.insert(id);
479 resourceIsAlreadyLoading = false;
482 if ( !resourceIsAlreadyLoading )
484 // load resource again
485 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
486 SendToClient( LoadingMessage( *mImpl->mResourceClient, id ) );
490 void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTypePath& typePath )
492 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleSaveResourceRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
494 bool resourceFound = false;
496 // ID must be in the complete sets
497 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
498 if (iter != mImpl->newCompleteRequests.end())
500 resourceFound = true;
504 LiveRequestIter iter = mImpl->oldCompleteRequests.find(id);
505 if (iter != mImpl->oldCompleteRequests.end())
507 resourceFound = true;
513 ResourcePointer resource;
514 DALI_ASSERT_DEBUG( typePath.type != NULL );
516 switch( typePath.type->id )
522 case ResourceNativeImage:
526 case ResourceTargetImage:
532 resource = GetShaderData(id);
537 resource = GetModelData(id);
550 if( resource ) // i.e. if it's a saveable resource
552 mImpl->saveRequests.insert(id);
554 ResourceRequest request(id, *typePath.type, typePath.path, resource);
555 mImpl->mPlatformAbstraction.SaveResource(request);
560 void ResourceManager::HandleDiscardResourceRequest( ResourceId deadId, ResourceTypeId typeId )
562 bool wasComplete = false;
563 bool wasLoading = false;
565 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleDiscardResourceRequest(id:%u)\n", deadId);
567 // remove copies of the deadId from completed/failed saving sets
568 RemoveId(mImpl->completeSaveRequests, deadId);
570 // Search for the ID in one of the live containers
571 // IDs are only briefly held in the new-completed or failed containers; check those last
572 // Try removing from the old-completed requests
573 bool foundLiveRequest = wasComplete = RemoveId(mImpl->oldCompleteRequests, deadId);
575 // Try removing from the loading requests
576 if (!foundLiveRequest)
578 foundLiveRequest = wasLoading = RemoveId(mImpl->loadingRequests, deadId);
581 // Try removing from the new completed requests
582 if (!foundLiveRequest)
584 foundLiveRequest = wasComplete = RemoveId(mImpl->newCompleteRequests, deadId);
587 // Try removing from the new failed requests
588 if (!foundLiveRequest)
590 foundLiveRequest = RemoveId(mImpl->newFailedRequests, deadId);
593 // Try removing from the old failed requests
594 if (!foundLiveRequest)
596 foundLiveRequest = RemoveId(mImpl->oldFailedRequests, deadId);
599 // ID should be in one of the live sets
600 if (!foundLiveRequest)
602 DALI_LOG_WARNING("HandleDiscardResourceRequest: ID should be in one of the live sets!\n");
604 DALI_ASSERT_DEBUG(foundLiveRequest);
608 if(typeId == ResourceBitmap ||
609 typeId == ResourceNativeImage ||
610 typeId == ResourceTargetImage )
612 // remove the meta data
613 mImpl->mBitmapMetadata.erase( deadId );
615 // destroy the texture
616 mImpl->mTextureCacheDispatcher.DispatchDiscardTexture( deadId );
620 // Move ID from completed to dead set
621 mImpl->deadRequests.insert(DeadRequestPair(deadId, typeId));
627 mImpl->mPlatformAbstraction.CancelLoad(deadId, typeId);
631 void ResourceManager::HandleAtlasUpdateRequest( ResourceId id, ResourceId atlasId, LoadStatus loadStatus )
633 mImpl->atlasStatus.Update(id, atlasId, loadStatus );
636 /********************************************************************************
637 ******************** Event thread object direct interface *********************
638 ********************************************************************************/
640 ModelDataPtr ResourceManager::GetModelData(ResourceId id)
642 ModelDataPtr modelData;
643 ModelCacheIter iter = mImpl->mModels.find(id);
644 if(iter != mImpl->mModels.end())
646 modelData = iter->second;
651 /********************************************************************************
652 ******************** Update thread object direct interface ********************
653 ********************************************************************************/
655 bool ResourceManager::IsResourceLoaded(ResourceId id)
661 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
662 if( iter != mImpl->newCompleteRequests.end() )
668 iter = mImpl->oldCompleteRequests.find(id);
669 if( iter != mImpl->oldCompleteRequests.end() )
679 bool ResourceManager::IsResourceLoadFailed(ResourceId id)
681 bool loadFailed = false;
685 LiveRequestIter iter = mImpl->newFailedRequests.find(id);
686 if( iter != mImpl->newFailedRequests.end() )
692 iter = mImpl->oldFailedRequests.find(id);
693 if( iter != mImpl->oldFailedRequests.end() )
703 BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id)
705 BitmapMetadata metadata;
709 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
710 if( iter != mImpl->mBitmapMetadata.end() )
712 metadata = iter->second;
719 Internal::SceneGraph::Mesh* ResourceManager::GetMesh(ResourceId id)
721 SceneGraph::Mesh* mesh = NULL;
722 MeshCacheIter iter = mImpl->mMeshes.find(id);
724 if (iter != mImpl->mMeshes.end())
732 ShaderDataPtr ResourceManager::GetShaderData(ResourceId id)
734 ShaderDataPtr shaderData;
735 ShaderCacheIter iter = mImpl->mShaders.find(id);
736 if(iter != mImpl->mShaders.end())
738 shaderData = iter->second;
743 bool ResourceManager::IsAtlasLoaded(ResourceId id)
745 return mImpl->atlasStatus.IsLoadComplete(id);
748 LoadStatus ResourceManager::GetAtlasLoadStatus( ResourceId atlasId )
750 return mImpl->atlasStatus.GetLoadStatus( atlasId );
753 /********************************************************************************
754 ************************* ResourceCache Implementation ************************
755 ********************************************************************************/
757 void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, ResourcePointer resource, LoadStatus loadStatus )
759 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
760 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");
762 // ID might be in the loading set
763 LiveRequestIter iter = mImpl->loadingRequests.find(id);
765 if ( iter != mImpl->loadingRequests.end() )
767 if( loadStatus == RESOURCE_COMPLETELY_LOADED )
769 // Remove from the loading set
770 mImpl->loadingRequests.erase(iter);
772 // Add the ID to the new-completed set, and store the resource
773 mImpl->newCompleteRequests.insert(id);
780 DALI_ASSERT_DEBUG( loadStatus == RESOURCE_COMPLETELY_LOADED && "Partial results not handled for image loading.\n" );
781 Bitmap* const bitmap = static_cast<Bitmap*>( resource.Get() );
784 DALI_LOG_ERROR( "Missing bitmap in loaded resource with id %u.\n", id );
787 unsigned int bitmapWidth = bitmap->GetImageWidth();
788 unsigned int bitmapHeight = bitmap->GetImageHeight();
790 if( Bitmap::PackedPixelsProfile * packedBitmap = bitmap->GetPackedPixelsProfile() )
792 bitmapWidth = packedBitmap->GetBufferWidth();
793 bitmapHeight = packedBitmap->GetBufferHeight();
795 Pixel::Format pixelFormat = bitmap->GetPixelFormat();
797 ImageAttributes attrs = ImageAttributes::New( bitmapWidth, bitmapHeight, pixelFormat ); ///!< Issue #AHC01
798 UpdateImageTicket (id, attrs);
800 // Check for reloaded bitmap
801 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
802 if (iter != mImpl->mBitmapMetadata.end())
804 iter->second.Update(bitmap);
805 mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( id, bitmap );
809 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
810 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
816 case ResourceNativeImage:
818 NativeImagePtr nativeImg( static_cast<NativeImage*>(resource.Get()) );
820 ImageAttributes attrs = ImageAttributes::New(nativeImg->GetWidth(), nativeImg->GetHeight(), nativeImg->GetPixelFormat());
822 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImg)));
823 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImg );
825 UpdateImageTicket (id, attrs);
829 case ResourceTargetImage:
836 mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
842 mImpl->mModels.insert(ModelDataPair(id, static_cast<ModelData*>(resource.Get())));
853 /* here we return a vector of Characters (glyph data + bitmap)*/
854 GlyphSetPointer glyphSet = static_cast<GlyphSet*>(resource.Get());
855 DALI_ASSERT_DEBUG( glyphSet );
856 UploadGlyphsToTexture(*glyphSet);
857 mImpl->atlasStatus.Update(id, glyphSet->GetAtlasResourceId(), loadStatus );
858 SendToClient( LoadingGlyphSetSucceededMessage( *mImpl->mResourceClient, id, glyphSet, loadStatus) );
863 // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
866 // flag that a load has completed and the cache updated
867 mImpl->cacheUpdated = true;
871 // This warning can fire if a cancelled load is forgotten here while already complete on a resource thread:
872 DALI_LOG_WARNING( "Received a notification for an untracked resource: (id:%u, status=%s)\n", id, loadStatus==RESOURCE_LOADING?"LOADING":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE");
876 void ResourceManager::SaveComplete(ResourceId id, ResourceTypeId type)
878 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
879 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveComplete(id:%u)\n", id);
881 // ID must be in the saving set
882 LiveRequestIter iter = mImpl->saveRequests.find(id);
884 if (iter != mImpl->saveRequests.end())
886 // Remove from the saving set
887 mImpl->saveRequests.erase(iter);
889 // If resource has not been discarded..
890 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
892 SendToClient( SavingSucceededMessage( *mImpl->mResourceClient, id ) );
895 mImpl->cacheUpdated = true;
899 void ResourceManager::LoadFailed(ResourceId id, ResourceFailure failure)
901 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: LoadFailed(id:%u)\n", id);
903 // ID might be in the loading set
904 LiveRequestIter iter = mImpl->loadingRequests.find(id);
906 if (iter != mImpl->loadingRequests.end())
908 // Remove from the loading set
909 mImpl->loadingRequests.erase(iter);
911 // Add the ID to the failed set, this will trigger a notification during UpdateTickets
912 mImpl->newFailedRequests.insert(id);
914 // Let NotificationManager know that the resource manager needs to do some processing
917 mImpl->cacheUpdated = true;
921 void ResourceManager::SaveFailed(ResourceId id, ResourceFailure failure)
923 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
924 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveFailed(id:%u)\n", id);
926 // ID must be in the saving set
927 LiveRequestIter iter = mImpl->saveRequests.find(id);
929 if (iter != mImpl->saveRequests.end())
931 // Remove from the saving set
932 mImpl->saveRequests.erase(iter);
934 // If resource has not been discarded..
936 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
938 SendToClient( SavingFailedMessage( *mImpl->mResourceClient, id ) );
941 mImpl->cacheUpdated = true;
945 /********************************************************************************
946 ********************************* Private Methods *****************************
947 ********************************************************************************/
949 void ResourceManager::ClearRequestedGlyphArea( ResourceId id, const ResourceTypePath& typePath )
951 if( typePath.type->id == ResourceText )
953 const TextResourceType *textResourceType = static_cast<const TextResourceType*>(typePath.type);
954 ResourceId atlasId = textResourceType->mTextureAtlasId;
956 BitmapClearArray clearAreas;
958 float blockSize = GlyphAtlasSize::GetBlockSize();
959 // Get x, y from each character:
960 for( TextResourceType::CharacterList::const_iterator iter = textResourceType->mCharacterList.begin(),
961 end = textResourceType->mCharacterList.end() ;
962 iter != end ; iter ++ )
964 Vector2 clearArea( iter->xPosition, iter->yPosition );
965 clearAreas.push_back(clearArea);
968 mImpl->mTextureCacheDispatcher.DispatchClearAreas( atlasId, clearAreas, blockSize, 0x00 );
972 void ResourceManager::UploadGlyphsToTexture( const GlyphSet& glyphSet )
974 // the glyphset contains an array of bitmap / characters .
975 // This function uploads the bitmaps to the associated texture atlas
977 const GlyphSet::CharacterList& charList( glyphSet.GetCharacterList() );
978 BitmapUploadArray uploadArray;
980 for(std::size_t i = 0, count = charList.size() ; i < count; i++ )
982 const GlyphSet::Character& character( charList[i] );
984 // grab a pointer to the bitmap
985 Bitmap* bitmap( character.first.Get() );
987 // create a bitmap upload object, then add it to the array
988 BitmapUpload upload( bitmap->ReleaseBuffer(), // Inform the bitmap we're taking ownership of it's pixel buffer.
989 character.second.xPosition, // x position in the texture to which upload the bitmap
990 character.second.yPosition, // y position in the texture to which upload the bitmap
991 bitmap->GetImageWidth(), // bitmap width
992 bitmap->GetImageHeight(), // bitmap height
993 BitmapUpload::DISCARD_PIXEL_DATA ); // tell the the texture to delete the bitmap pixel buffer when it's done
995 uploadArray.push_back( upload );
998 ResourceId textureId = glyphSet.GetAtlasResourceId();
999 if( IsResourceLoaded( textureId ) )
1001 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( textureId, uploadArray );
1006 void ResourceManager::NotifyTickets()
1008 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1009 // Success notifications
1010 for (LiveRequestIter iter = mImpl->newCompleteRequests.begin(); iter != mImpl->newCompleteRequests.end(); ++iter)
1012 // Move to oldCompleteRequests
1013 mImpl->oldCompleteRequests.insert(*iter);
1015 SendToClient( LoadingSucceededMessage( *mImpl->mResourceClient, *iter ) );
1017 mImpl->newCompleteRequests.clear();
1019 // Failure notifications
1020 for (LiveRequestIter iter = mImpl->newFailedRequests.begin(); iter != mImpl->newFailedRequests.end(); ++iter)
1022 // Move to oldFailedRequests
1023 mImpl->oldFailedRequests.insert(*iter);
1025 // We should have a matching request ticket
1026 SendToClient( LoadingFailedMessage( *mImpl->mResourceClient, *iter ) );
1028 mImpl->newFailedRequests.clear();
1031 void ResourceManager::UpdateImageTicket( ResourceId id, ImageAttributes& attributes ) ///!< Issue #AHC01
1033 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1034 // ResourceLoader should load images considering the requested size
1035 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: UpdateImageTicket(id:%u)\n", id);
1037 // Let NotificationManager know that the resource manager needs to do some processing
1038 SendToClient( UpdateImageTicketMessage( *mImpl->mResourceClient, id, attributes) );
1041 void ResourceManager::SendToClient( MessageBase* message )
1043 mImpl->mNotificationManager.QueueMessage( message );
1046 void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex )
1048 for (DeadRequestIter iter = mImpl->deadRequests.begin(); iter != mImpl->deadRequests.end(); )
1050 // Delay destroying ids in saveRequests
1051 if( mImpl->saveRequests.find(iter->first) != mImpl->saveRequests.end())
1058 * We should find a resource of the correct type, and move it to the DiscardQueue.
1060 switch (iter->second)
1062 case ResourceBitmap:
1063 case ResourceNativeImage:
1064 case ResourceTargetImage:
1069 ModelCacheIter model = mImpl->mModels.find(iter->first);
1070 DALI_ASSERT_DEBUG( mImpl->mModels.end() != model );
1072 // model data is owned through intrusive pointers so no need for discard queue
1073 mImpl->mModels.erase( model );
1079 MeshCacheIter mesh = mImpl->mMeshes.find(iter->first);
1080 DALI_ASSERT_DEBUG( mImpl->mMeshes.end() != mesh );
1081 if( mImpl->mMeshes.end() != mesh )
1083 mImpl->mDiscardQueue.Add( updateBufferIndex, mesh->second );
1084 mImpl->mMeshes.erase( mesh );
1094 case ResourceShader:
1096 ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first);
1097 DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
1098 // shader data is owned through intrusive pointers so no need for discard queue
1099 mImpl->mShaders.erase( shaderIter );
1104 mImpl->atlasStatus.Remove(iter->first);
1106 // Erase the item and increment the iterator
1107 mImpl->deadRequests.erase(iter++);
1111 } // namespace Internal