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>
52 using namespace Dali::Integration;
54 using Dali::Internal::SceneGraph::DiscardQueue;
55 using Dali::Internal::SceneGraph::RenderQueue;
56 using Dali::Internal::SceneGraph::TextureCacheDispatcher;
63 typedef set<ResourceId> LiveRequestContainer;
64 typedef LiveRequestContainer::iterator LiveRequestIter;
65 typedef LiveRequestContainer::size_type LiveRequestSize;
67 typedef map<ResourceId, ResourceTypeId> DeadRequestContainer;
68 typedef DeadRequestContainer::iterator DeadRequestIter;
69 typedef pair<ResourceId, ResourceTypeId> DeadRequestPair;
71 typedef vector<ResourceId> NotifyQueue;
72 typedef NotifyQueue::iterator NotifyQueueIter;
74 typedef map<ResourceId, BitmapMetadata> BitmapMetadataCache;
75 typedef BitmapMetadataCache::iterator BitmapMetadataIter;
76 typedef pair<ResourceId, BitmapMetadata> BitmapMetadataPair;
78 typedef map<ResourceId, ModelDataPtr> ModelCache;
79 typedef ModelCache::iterator ModelCacheIter;
80 typedef pair<ResourceId, ModelDataPtr> ModelDataPair;
82 typedef map<ResourceId, SceneGraph::Mesh*> MeshCache;
83 typedef MeshCache::iterator MeshCacheIter;
84 typedef pair<ResourceId, SceneGraph::Mesh*> MeshDataPair;
86 typedef map<ResourceId, ShaderDataPtr> ShaderCache;
87 typedef ShaderCache::iterator ShaderCacheIter;
88 typedef ShaderCache::size_type ShaderCacheSize;
89 typedef pair<ResourceId, ShaderDataPtr> ShaderDataPair;
91 struct ResourceManager::ResourceManagerImpl
93 ResourceManagerImpl( PlatformAbstraction& platformAbstraction,
94 NotificationManager& notificationManager,
95 SceneGraph::TextureCacheDispatcher& textureCacheDispatcher,
96 ResourcePostProcessList& resourcePostProcessQueue,
97 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
98 DiscardQueue& discardQueue,
99 RenderQueue& renderQueue )
100 : mPlatformAbstraction(platformAbstraction),
101 mNotificationManager(notificationManager),
102 mResourceClient(NULL),
103 mTextureCacheDispatcher(textureCacheDispatcher),
104 mResourcePostProcessQueue(resourcePostProcessQueue),
105 mPostProcessResourceDispatcher(postProcessResourceDispatcher),
106 mDiscardQueue(discardQueue),
107 mRenderQueue(renderQueue),
108 mNotificationCount(0)
112 ~ResourceManagerImpl()
114 // Cleanup existing meshes
115 for( MeshCacheIter it = mMeshes.begin();
123 PlatformAbstraction& mPlatformAbstraction;
124 NotificationManager& mNotificationManager;
125 ResourceClient* mResourceClient; // (needs to be a ptr - it's not instantiated yet)
126 TextureCacheDispatcher& mTextureCacheDispatcher;
127 ResourcePostProcessList& mResourcePostProcessQueue;
128 SceneGraph::PostProcessResourceDispatcher& mPostProcessResourceDispatcher;
129 DiscardQueue& mDiscardQueue; ///< Unwanted resources are added here during UpdateCache()
130 RenderQueue& mRenderQueue;
131 unsigned int mNotificationCount;
132 bool cacheUpdated; ///< returned by UpdateCache(). Set true in NotifyTickets to indicate a change in a resource
135 * These containers are used to processs requests, and ResourceCache callbacks.
136 * The live request containers are simply sets of integer resource ids.
137 * The ID of a new request will be placed in the loading container.
138 * If the Ticket is destroyed during the load, the ID will be removed.
139 * If the load fails, the ID will be moved to the failed container.
140 * When the Ticket is notified of the failure, the ID will be removed.
141 * If the load succeeds, the ID will be moved to the new-completed container.
142 * When the Ticket is notified of the completion, the ID will be moved to the old-completed container.
143 * If a Ticket is destroyed after a successful load, the ID will be moved to the dead container.
144 * When the resources are eventually deleted, the ID will be removed from the dead container.
146 LiveRequestContainer loadingRequests;
147 LiveRequestContainer newCompleteRequests;
148 LiveRequestContainer oldCompleteRequests;
149 LiveRequestContainer newFailedRequests;
150 LiveRequestContainer oldFailedRequests;
151 DeadRequestContainer deadRequests;
152 LiveRequestContainer saveRequests; ///< copy of id's being saved (must also be in newCompleteRequests or oldCompleteRequests)
153 LiveRequestContainer completeSaveRequests; ///< successful save ids are moved from saveRequests to here
155 AtlasRequestStatus atlasStatus; ///< load status of text atlases
158 * This is the resource cache. It's filled/emptied from within Core::Update()
160 BitmapMetadataCache mBitmapMetadata;
163 ShaderCache mShaders;
166 ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
167 NotificationManager& notificationManager,
168 TextureCacheDispatcher& textureCacheDispatcher,
169 ResourcePostProcessList& resourcePostProcessQueue,
170 SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
171 DiscardQueue& discardQueue,
172 RenderQueue& renderQueue )
174 mImpl = new ResourceManagerImpl( platformAbstraction,
176 textureCacheDispatcher,
177 resourcePostProcessQueue,
178 postProcessResourceDispatcher,
183 ResourceManager::~ResourceManager()
188 /********************************************************************************
189 ************************ ResourceClient direct interface **********************
190 ********************************************************************************/
192 void ResourceManager::SetClient( ResourceClient& client )
194 mImpl->mResourceClient = &client;
197 /********************************************************************************
198 ************************ UpdateManager direct interface ***********************
199 ********************************************************************************/
201 bool ResourceManager::UpdateCache( BufferIndex updateBufferIndex )
203 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: UpdateCache(bufferIndex:%u)\n", updateBufferIndex);
205 // 1) Move unwanted resources to the DiscardQueue
207 DiscardDeadResources( updateBufferIndex );
209 // 2) Fill the resource cache
210 mImpl->cacheUpdated = false;
212 mImpl->mPlatformAbstraction.GetResources(*this);
214 return mImpl->cacheUpdated;
217 void ResourceManager::PostProcessResources( BufferIndex updateBufferIndex )
219 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
220 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: PostProcessResources()\n");
222 unsigned int numIds = mImpl->mResourcePostProcessQueue[ updateBufferIndex ].size();
225 // process the list where RenderManager put post process requests
226 for (i = 0; i < numIds; ++i)
228 ResourcePostProcessRequest ppRequest = mImpl->mResourcePostProcessQueue[ updateBufferIndex ][i];
229 switch(ppRequest.postProcess)
231 case ResourcePostProcessRequest::UPLOADED:
232 SendToClient( UploadedMessage( *mImpl->mResourceClient, ppRequest.id ) );
234 case ResourcePostProcessRequest::SAVE:
235 SendToClient( SaveResourceMessage( *mImpl->mResourceClient, ppRequest.id ) );
237 case ResourcePostProcessRequest::DELETED:
238 // TextureObservers handled in TextureCache
243 mImpl->mResourcePostProcessQueue[ updateBufferIndex ].clear();
247 /********************************************************************************
248 *************************** CoreImpl direct interface *************************
249 ********************************************************************************/
251 bool ResourceManager::ResourcesToProcess()
253 bool workTodo = false;
255 // need to make sure we have passed all the notifications to the event handling side
256 workTodo |= !mImpl->newCompleteRequests.empty();
257 workTodo |= !mImpl->newFailedRequests.empty();
258 // check if there's something still loading
259 workTodo |= !mImpl->loadingRequests.empty();
260 workTodo |= !mImpl->saveRequests.empty();
266 /********************************************************************************
267 ********************************* Message handlers *****************************
268 ********************************************************************************/
270 void ResourceManager::HandleLoadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
272 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);
274 // Add ID to the loading set
275 mImpl->loadingRequests.insert(id);
277 // Update atlas status if this request is a text request
278 mImpl->atlasStatus.CheckAndSaveTextRequest(id, typePath);
280 ClearRequestedGlyphArea(id, typePath);
282 // Make the load request last
283 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
286 void ResourceManager::HandleDecodeResourceRequest(
288 const ResourceTypePath& typePath,
289 RequestBufferPtr buffer,
290 Integration::LoadResourcePriority priority )
292 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);
294 // We would update atlas status and clear the glyph area if text were supported and this request was a text request:
295 if( typePath.type->id == ResourceText )
297 DALI_LOG_WARNING("Decoding from memory buffers not supported for Text resources.");
301 // Add ID to the loading set
302 mImpl->loadingRequests.insert(id);
304 // Make the load request, stuffing the buffer of encoded bytes into the same field used when saving resources:
305 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, "", buffer, priority));
308 void ResourceManager::HandleAddBitmapImageRequest( ResourceId id, Bitmap* bitmap )
310 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
311 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddBitmapImageRequest(id:%u)\n", id);
313 mImpl->oldCompleteRequests.insert(id);
314 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
315 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
318 void ResourceManager::HandleAddNativeImageRequest(ResourceId id, NativeImagePtr nativeImage)
320 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
321 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddNativeImageRequest(id:%u)\n", id);
323 mImpl->oldCompleteRequests.insert(id);
325 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImage)));
326 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImage );
329 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
331 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
332 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
334 mImpl->oldCompleteRequests.insert(id);
336 BitmapMetadata bitmapMetadata = BitmapMetadata::New(width, height, pixelFormat);
337 bitmapMetadata.SetIsFramebuffer(true);
338 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
340 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, width, height, pixelFormat );
343 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, NativeImagePtr nativeImage )
345 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
346 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
348 mImpl->oldCompleteRequests.insert(id);
350 BitmapMetadata bitmapMetadata = BitmapMetadata::New(nativeImage->GetWidth(), nativeImage->GetHeight(), nativeImage->GetPixelFormat());
351 bitmapMetadata.SetIsNativeImage(true);
352 bitmapMetadata.SetIsFramebuffer(true);
353 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
355 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, nativeImage );
358 void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
360 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateTextureRequest(id:%u)\n", id);
362 mImpl->oldCompleteRequests.insert(id);
363 mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ );
366 void ResourceManager::HandleUpdateTextureRequest( ResourceId id, const BitmapUploadArray& uploadArray )
368 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( id, uploadArray );
371 void ResourceManager::HandleAllocateMeshRequest( ResourceId id, MeshData* meshData )
373 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateMeshRequest(id:%u)\n", id);
375 SceneGraph::Mesh* renderableMesh(SceneGraph::Mesh::New(id, mImpl->mPostProcessResourceDispatcher, meshData));
377 DALI_ASSERT_ALWAYS(renderableMesh && "renderableMesh not created");
379 // Add the ID to the completed set, and store the resource
380 mImpl->newCompleteRequests.insert(id);
381 mImpl->mMeshes.insert(MeshDataPair(id, renderableMesh));
383 // Let NotificationManager know that the resource manager needs to do some processing
387 void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath )
389 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
391 const ShaderResourceType* shaderType = dynamic_cast<const ShaderResourceType*>(typePath.type);
392 DALI_ASSERT_DEBUG(shaderType);
396 ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader));
398 // For startup speed, shader file load must be synchronous in this
399 // thread - Update manager will get a message following this to use
400 // the program data immediately. (i.e. if this load fails, then
403 // It would be safer, though slower, to handle shader binary load
404 // failure in the event thread through the ticket mechanism;
405 // however, as we are not using the result in the ShaderFactory, it
406 // is safe to return LoadSuccess even if the load failed. Ignore the
408 mImpl->mPlatformAbstraction.LoadFile(typePath.path, shaderData->buffer);
410 // Add the ID to the completed set
411 mImpl->newCompleteRequests.insert(id);
413 // Cache the resource
414 mImpl->mShaders.insert(ShaderDataPair(id, shaderData));
416 // Let NotificationManager know that the resource manager needs to do some processing
421 void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area )
425 mImpl->mTextureCacheDispatcher.DispatchUpdateTextureArea( textureId, area );
429 void ResourceManager::HandleUpdateMeshRequest( BufferIndex updateBufferIndex, ResourceId id, MeshData* meshData )
431 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
432 SceneGraph::Mesh* mesh = GetMesh( id );
433 DALI_ASSERT_DEBUG(mesh);
435 // Update the mesh data
436 mesh->SetMeshData( meshData );
438 // Update the GL buffers in the next Render
439 typedef MessageDoubleBuffered2< SceneGraph::Mesh, SceneGraph::Mesh::ThreadBuffer, OwnerPointer<MeshData> > DerivedType;
441 // Reserve some memory inside the render queue
442 unsigned int* slot = mImpl->mRenderQueue.ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
444 // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
445 new (slot) DerivedType( mesh, &SceneGraph::Mesh::MeshDataUpdated, SceneGraph::Mesh::RENDER_THREAD, meshData );
448 void ResourceManager::HandleReloadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
450 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
451 DALI_LOG_INFO( Debug::Filter::gResource, Debug::General, "ResourceManager: HandleReloadRequest(id:%u, path:%s)\n", id, typePath.path.c_str() );
453 bool resourceIsAlreadyLoading = true;
455 // ID might be in the loading set
456 LiveRequestIter iter = mImpl->loadingRequests.find( id );
457 if ( iter == mImpl->loadingRequests.end() )
459 // Add ID to the loading set
460 mImpl->loadingRequests.insert(id);
461 resourceIsAlreadyLoading = false;
464 if ( !resourceIsAlreadyLoading )
466 //load resource again
467 mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
468 SendToClient( LoadingMessage( *mImpl->mResourceClient, id ) );
472 void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTypePath& typePath )
474 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleSaveResourceRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
476 bool resourceFound = false;
478 // ID must be in the complete sets
479 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
480 if (iter != mImpl->newCompleteRequests.end())
482 resourceFound = true;
486 LiveRequestIter iter = mImpl->oldCompleteRequests.find(id);
487 if (iter != mImpl->oldCompleteRequests.end())
489 resourceFound = true;
495 ResourcePointer resource;
496 DALI_ASSERT_DEBUG( typePath.type != NULL );
498 switch( typePath.type->id )
504 case ResourceNativeImage:
508 case ResourceTargetImage:
514 resource = GetShaderData(id);
519 resource = GetModelData(id);
532 if( resource ) // i.e. if it's a saveable resource
534 mImpl->saveRequests.insert(id);
536 ResourceRequest request(id, *typePath.type, typePath.path, resource);
537 mImpl->mPlatformAbstraction.SaveResource(request);
542 static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
544 return container.erase(id) != 0;
547 void ResourceManager::HandleDiscardResourceRequest( ResourceId deadId, ResourceTypeId typeId )
549 bool wasComplete = false;
550 bool wasLoading = false;
552 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleDiscardResourceRequest(id:%u)\n", deadId);
554 // remove copies of the deadId from completed/failed saving sets
555 RemoveId(mImpl->completeSaveRequests, deadId);
557 // Search for the ID in one of the live containers
558 // IDs are only briefly held in the new-completed or failed containers; check those last
559 bool foundLiveRequest = false;
561 // Try removing from the old-completed requests
562 foundLiveRequest = wasComplete = RemoveId(mImpl->oldCompleteRequests, deadId);
564 // Try removing from the loading requests
565 if (!foundLiveRequest)
567 foundLiveRequest = wasLoading = RemoveId(mImpl->loadingRequests, deadId);
570 // Try removing from the new completed requests
571 if (!foundLiveRequest)
573 foundLiveRequest = wasComplete = RemoveId(mImpl->newCompleteRequests, deadId);
576 // Try removing from the new failed requests
577 if (!foundLiveRequest)
579 foundLiveRequest = RemoveId(mImpl->newFailedRequests, deadId);
582 // Try removing from the old failed requests
583 if (!foundLiveRequest)
585 foundLiveRequest = RemoveId(mImpl->oldFailedRequests, deadId);
588 // ID should be in one of the live sets
589 if (!foundLiveRequest)
591 DALI_LOG_WARNING("HandleDiscardResourceRequest: ID should be in one of the live sets!\n");
593 DALI_ASSERT_DEBUG(foundLiveRequest);
597 if(typeId == ResourceBitmap ||
598 typeId == ResourceNativeImage ||
599 typeId == ResourceTargetImage )
601 // remove the meta data
602 mImpl->mBitmapMetadata.erase( deadId );
604 // destroy the texture
605 mImpl->mTextureCacheDispatcher.DispatchDiscardTexture( deadId );
609 // Move ID from completed to dead set
610 mImpl->deadRequests.insert(DeadRequestPair(deadId, typeId));
616 mImpl->mPlatformAbstraction.CancelLoad(deadId, typeId);
620 void ResourceManager::HandleAtlasUpdateRequest( ResourceId id, ResourceId atlasId, LoadStatus loadStatus )
622 mImpl->atlasStatus.Update(id, atlasId, loadStatus );
625 /********************************************************************************
626 ******************** Event thread object direct interface *********************
627 ********************************************************************************/
629 ModelDataPtr ResourceManager::GetModelData(ResourceId id)
631 ModelDataPtr modelData;
632 ModelCacheIter iter = mImpl->mModels.find(id);
633 if(iter != mImpl->mModels.end())
635 modelData = iter->second;
640 /********************************************************************************
641 ******************** Update thread object direct interface ********************
642 ********************************************************************************/
644 bool ResourceManager::IsResourceLoaded(ResourceId id)
650 LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
651 if( iter != mImpl->newCompleteRequests.end() )
657 iter = mImpl->oldCompleteRequests.find(id);
658 if( iter != mImpl->oldCompleteRequests.end() )
668 bool ResourceManager::IsResourceLoadFailed(ResourceId id)
670 bool loadFailed = false;
674 LiveRequestIter iter = mImpl->newFailedRequests.find(id);
675 if( iter != mImpl->newFailedRequests.end() )
681 iter = mImpl->oldFailedRequests.find(id);
682 if( iter != mImpl->oldFailedRequests.end() )
692 BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id)
694 BitmapMetadata metadata;
698 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
699 if( iter != mImpl->mBitmapMetadata.end() )
701 metadata = iter->second;
708 Internal::SceneGraph::Mesh* ResourceManager::GetMesh(ResourceId id)
710 SceneGraph::Mesh* mesh = NULL;
711 MeshCacheIter iter = mImpl->mMeshes.find(id);
713 if (iter != mImpl->mMeshes.end())
721 ShaderDataPtr ResourceManager::GetShaderData(ResourceId id)
723 ShaderDataPtr shaderData;
724 ShaderCacheIter iter = mImpl->mShaders.find(id);
725 if(iter != mImpl->mShaders.end())
727 shaderData = iter->second;
732 bool ResourceManager::IsAtlasLoaded(ResourceId id)
734 return mImpl->atlasStatus.IsLoadComplete(id);
737 LoadStatus ResourceManager::GetAtlasLoadStatus( ResourceId atlasId )
739 return mImpl->atlasStatus.GetLoadStatus( atlasId );
742 /********************************************************************************
743 ************************* ResourceCache Implementation ************************
744 ********************************************************************************/
746 void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, ResourcePointer resource, LoadStatus loadStatus )
748 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
749 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");
751 // ID might be in the loading set
752 LiveRequestIter iter = mImpl->loadingRequests.find(id);
754 if ( iter != mImpl->loadingRequests.end() )
756 if( loadStatus == RESOURCE_COMPLETELY_LOADED )
758 // Remove from the loading set
759 mImpl->loadingRequests.erase(iter);
761 // Add the ID to the new-completed set, and store the resource
762 mImpl->newCompleteRequests.insert(id);
769 DALI_ASSERT_DEBUG( loadStatus == RESOURCE_COMPLETELY_LOADED && "Partial results not handled for image loading.\n" );
770 Bitmap* const bitmap = static_cast<Bitmap*>( resource.Get() );
773 DALI_LOG_ERROR( "Missing bitmap in loaded resource with id %u.\n", id );
776 unsigned int bitmapWidth = bitmap->GetImageWidth();
777 unsigned int bitmapHeight = bitmap->GetImageHeight();
779 if( Bitmap::PackedPixelsProfile * packedBitmap = bitmap->GetPackedPixelsProfile() )
781 bitmapWidth = packedBitmap->GetBufferWidth();
782 bitmapHeight = packedBitmap->GetBufferHeight();
784 Pixel::Format pixelFormat = bitmap->GetPixelFormat();
786 ImageAttributes attrs = ImageAttributes::New( bitmapWidth, bitmapHeight, pixelFormat ); ///!< Issue #AHC01
787 UpdateImageTicket (id, attrs);
789 // Check for reloaded bitmap
790 BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
791 if (iter != mImpl->mBitmapMetadata.end())
793 iter->second.Update(bitmap);
794 mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( id, bitmap );
798 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
799 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
805 case ResourceNativeImage:
807 NativeImagePtr nativeImg( static_cast<NativeImage*>(resource.Get()) );
809 ImageAttributes attrs = ImageAttributes::New(nativeImg->GetWidth(), nativeImg->GetHeight(), nativeImg->GetPixelFormat());
811 mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImg)));
812 mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImg );
814 UpdateImageTicket (id, attrs);
818 case ResourceTargetImage:
825 mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
831 mImpl->mModels.insert(ModelDataPair(id, static_cast<ModelData*>(resource.Get())));
842 /* here we return a vector of Characters (glyph data + bitmap)*/
843 GlyphSetPointer glyphSet = static_cast<GlyphSet*>(resource.Get());
844 DALI_ASSERT_DEBUG( glyphSet );
845 UploadGlyphsToTexture(*glyphSet);
846 mImpl->atlasStatus.Update(id, glyphSet->GetAtlasResourceId(), loadStatus );
847 SendToClient( LoadingGlyphSetSucceededMessage( *mImpl->mResourceClient, id, glyphSet, loadStatus) );
852 // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
855 // flag that a load has completed and the cache updated
856 mImpl->cacheUpdated = true;
860 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");
864 void ResourceManager::SaveComplete(ResourceId id, ResourceTypeId type)
866 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
867 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveComplete(id:%u)\n", id);
869 // ID must be in the saving set
870 LiveRequestIter iter = mImpl->saveRequests.find(id);
872 if (iter != mImpl->saveRequests.end())
874 // Remove from the saving set
875 mImpl->saveRequests.erase(iter);
877 // If resource has not been discarded..
878 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
880 SendToClient( SavingSucceededMessage( *mImpl->mResourceClient, id ) );
883 // clear the uneeded binary shader data
884 if( type == ResourceShader )
886 ShaderCacheIter shaderIter = mImpl->mShaders.find(id);
887 DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
888 ShaderDataPtr shaderDataPtr = shaderIter->second;
889 std::vector<unsigned char>().swap(shaderDataPtr->buffer);
894 void ResourceManager::LoadFailed(ResourceId id, ResourceFailure failure)
896 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: LoadFailed(id:%u)\n", id);
898 // ID might be in the loading set
899 LiveRequestIter iter = mImpl->loadingRequests.find(id);
901 if (iter != mImpl->loadingRequests.end())
903 // Remove from the loading set
904 mImpl->loadingRequests.erase(iter);
906 // Add the ID to the failed set, this will trigger a notification during UpdateTickets
907 mImpl->newFailedRequests.insert(id);
909 // Let NotificationManager know that the resource manager needs to do some processing
914 void ResourceManager::SaveFailed(ResourceId id, ResourceFailure failure)
916 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
917 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveFailed(id:%u)\n", id);
919 // ID must be in the saving set
920 LiveRequestIter iter = mImpl->saveRequests.find(id);
922 if (iter != mImpl->saveRequests.end())
924 // Remove from the saving set
925 mImpl->saveRequests.erase(iter);
927 // If resource has not been discarded..
929 if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
931 SendToClient( SavingFailedMessage( *mImpl->mResourceClient, id ) );
936 /********************************************************************************
937 ********************************* Private Methods *****************************
938 ********************************************************************************/
940 void ResourceManager::ClearRequestedGlyphArea( ResourceId id, const ResourceTypePath& typePath )
942 if( typePath.type->id == ResourceText )
944 const TextResourceType *textResourceType = static_cast<const TextResourceType*>(typePath.type);
945 ResourceId atlasId = textResourceType->mTextureAtlasId;
947 BitmapClearArray clearAreas;
949 float blockSize = GlyphAtlasSize::GetBlockSize();
950 // Get x, y from each character:
951 for( TextResourceType::CharacterList::const_iterator iter = textResourceType->mCharacterList.begin(),
952 end = textResourceType->mCharacterList.end() ;
953 iter != end ; iter ++ )
956 clearArea.x= iter->xPosition;
957 clearArea.y= iter->yPosition;
958 clearAreas.push_back(clearArea);
961 mImpl->mTextureCacheDispatcher.DispatchClearAreas( atlasId, clearAreas, blockSize, 0x00 );
965 void ResourceManager::UploadGlyphsToTexture( const GlyphSet& glyphSet )
967 // the glyphset contains an array of bitmap / characters .
968 // This function uploads the bitmaps to the associated texture atlas
970 const GlyphSet::CharacterList& charList( glyphSet.GetCharacterList() );
971 BitmapUploadArray uploadArray;
973 for(std::size_t i = 0, count = charList.size() ; i < count; i++ )
975 const GlyphSet::Character& character( charList[i] );
977 // grab a pointer to the bitmap
978 Bitmap* bitmap( character.first.Get() );
980 // create a bitmap upload object, then add it to the array
981 BitmapUpload upload( bitmap->ReleaseBuffer(), // Inform the bitmap we're taking ownership of it's pixel buffer.
982 character.second.xPosition, // x position in the texture to which upload the bitmap
983 character.second.yPosition, // y position in the texture to which upload the bitmap
984 bitmap->GetImageWidth(), // bitmap width
985 bitmap->GetImageHeight(), // bitmap height
986 BitmapUpload::DISCARD_PIXEL_DATA ); // tell the the texture to delete the bitmap pixel buffer when it's done
988 uploadArray.push_back( upload );
991 ResourceId textureId = glyphSet.GetAtlasResourceId();
992 if( IsResourceLoaded( textureId ) )
994 mImpl->mTextureCacheDispatcher.DispatchUploadBitmapArrayToTexture( textureId, uploadArray );
999 void ResourceManager::NotifyTickets()
1001 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1002 // Success notifications
1003 for (LiveRequestIter iter = mImpl->newCompleteRequests.begin(); iter != mImpl->newCompleteRequests.end(); ++iter)
1005 // Move to oldCompleteRequests
1006 mImpl->oldCompleteRequests.insert(*iter);
1008 SendToClient( LoadingSucceededMessage( *mImpl->mResourceClient, *iter ) );
1010 mImpl->newCompleteRequests.clear();
1012 // Failure notifications
1013 for (LiveRequestIter iter = mImpl->newFailedRequests.begin(); iter != mImpl->newFailedRequests.end(); ++iter)
1015 // Move to oldFailedRequests
1016 mImpl->oldFailedRequests.insert(*iter);
1018 // We should have a matching request ticket
1019 SendToClient( LoadingFailedMessage( *mImpl->mResourceClient, *iter ) );
1021 mImpl->newFailedRequests.clear();
1024 void ResourceManager::UpdateImageTicket( ResourceId id, ImageAttributes& attributes ) ///!< Issue #AHC01
1026 DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
1027 // ResourceLoader should load images considering the requested size
1028 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: UpdateImageTicket(id:%u)\n", id);
1030 // Let NotificationManager know that the resource manager needs to do some processing
1031 SendToClient( UpdateImageTicketMessage( *mImpl->mResourceClient, id, attributes) );
1034 void ResourceManager::SendToClient( MessageBase* message )
1036 mImpl->mNotificationManager.QueueMessage( message );
1039 void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex )
1041 for (DeadRequestIter iter = mImpl->deadRequests.begin(); iter != mImpl->deadRequests.end(); )
1043 // Delay destroying ids in saveRequests
1044 if( mImpl->saveRequests.find(iter->first) != mImpl->saveRequests.end())
1051 * We should find a resource of the correct type, and move it to the DiscardQueue.
1053 switch (iter->second)
1055 case ResourceBitmap:
1056 case ResourceNativeImage:
1057 case ResourceTargetImage:
1062 ModelCacheIter model = mImpl->mModels.find(iter->first);
1063 DALI_ASSERT_DEBUG( mImpl->mModels.end() != model );
1065 mImpl->mDiscardQueue.Add( updateBufferIndex, *(model->second) );
1066 mImpl->mModels.erase( model );
1072 MeshCacheIter mesh = mImpl->mMeshes.find(iter->first);
1073 DALI_ASSERT_DEBUG( mImpl->mMeshes.end() != mesh );
1075 mImpl->mDiscardQueue.Add( updateBufferIndex, mesh->second );
1076 mImpl->mMeshes.erase( mesh );
1085 case ResourceShader:
1087 ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first);
1088 DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
1090 mImpl->mDiscardQueue.Add( updateBufferIndex, *(shaderIter->second) );
1091 mImpl->mShaders.erase( shaderIter );
1096 mImpl->atlasStatus.Remove(iter->first);
1098 // Erase the item and increment the iterator
1099 mImpl->deadRequests.erase(iter++);
1103 } // namespace Internal