1cfba74c11bc5614fe7cf468ca6883d40bf61a2d
[platform/core/uifw/dali-core.git] / dali / internal / update / resources / resource-manager.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/resources/resource-manager.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdio.h>
23 #include <typeinfo>
24
25 // INTERNAL INCLUDES
26 #include <dali/devel-api/common/map-wrapper.h>
27 #include <dali/devel-api/common/set-wrapper.h>
28 #include <dali/public-api/math/vector2.h>
29
30 #include <dali/integration-api/debug.h>
31
32 #include <dali/internal/common/message.h>
33 #include <dali/internal/common/image-attributes.h>
34
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
39 #include <dali/internal/update/modeling/scene-graph-mesh.h>
40 #include <dali/internal/update/common/discard-queue.h>
41 #include <dali/internal/update/resources/bitmap-metadata.h>
42 #include <dali/internal/render/queue/render-queue.h>
43
44 #include <dali/internal/render/common/texture-cache-dispatcher.h>
45 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
46
47 using namespace Dali::Integration;
48
49 using Dali::Internal::SceneGraph::DiscardQueue;
50 using Dali::Internal::SceneGraph::RenderQueue;
51 using Dali::Internal::SceneGraph::TextureCacheDispatcher;
52
53 namespace Dali
54 {
55 namespace Internal
56 {
57
58 typedef std::set<ResourceId>                     LiveRequestContainer;
59 typedef LiveRequestContainer::iterator           LiveRequestIter;
60 typedef LiveRequestContainer::size_type          LiveRequestSize;
61
62 typedef std::map<ResourceId, ResourceTypeId>     DeadRequestContainer;
63 typedef DeadRequestContainer::iterator           DeadRequestIter;
64 typedef std::pair<ResourceId, ResourceTypeId>    DeadRequestPair;
65
66 typedef std::vector<ResourceId>                  NotifyQueue;
67 typedef NotifyQueue::iterator                    NotifyQueueIter;
68
69 typedef std::map<ResourceId, BitmapMetadata>     BitmapMetadataCache;
70 typedef BitmapMetadataCache::iterator            BitmapMetadataIter;
71 typedef std::pair<ResourceId, BitmapMetadata>    BitmapMetadataPair;
72
73 typedef std::map<ResourceId, SceneGraph::Mesh*>  MeshCache;
74 typedef MeshCache::iterator                      MeshCacheIter;
75 typedef std::pair<ResourceId, SceneGraph::Mesh*> MeshDataPair;
76
77 typedef std::map<ResourceId, ShaderDataPtr>      ShaderCache;
78 typedef ShaderCache::iterator                    ShaderCacheIter;
79 typedef ShaderCache::size_type                   ShaderCacheSize;
80 typedef std::pair<ResourceId, ShaderDataPtr>     ShaderDataPair;
81
82 static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
83 {
84   return container.erase(id) != 0;
85 }
86
87 struct ResourceManager::ResourceManagerImpl
88 {
89   ResourceManagerImpl( PlatformAbstraction& platformAbstraction,
90                        NotificationManager& notificationManager,
91                        SceneGraph::TextureCacheDispatcher& textureCacheDispatcher,
92                        ResourcePostProcessList& resourcePostProcessQueue,
93                        SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
94                        DiscardQueue& discardQueue,
95                        RenderQueue& renderQueue )
96   : mPlatformAbstraction(platformAbstraction),
97     mNotificationManager(notificationManager),
98     mResourceClient(NULL),
99     mTextureCacheDispatcher(textureCacheDispatcher),
100     mResourcePostProcessQueue(resourcePostProcessQueue),
101     mPostProcessResourceDispatcher(postProcessResourceDispatcher),
102     mDiscardQueue(discardQueue),
103     mRenderQueue(renderQueue),
104     mNotificationCount(0),
105     cacheUpdated(false)
106   {
107   }
108
109   ~ResourceManagerImpl()
110   {
111     // Cleanup existing meshes
112     for( MeshCacheIter it = mMeshes.begin();
113          it != mMeshes.end();
114          ++it )
115     {
116       delete it->second;
117     }
118   }
119
120   PlatformAbstraction&     mPlatformAbstraction;
121   NotificationManager&     mNotificationManager;
122   ResourceClient*          mResourceClient; // (needs to be a ptr - it's not instantiated yet)
123   TextureCacheDispatcher&  mTextureCacheDispatcher;
124   ResourcePostProcessList& mResourcePostProcessQueue;
125   SceneGraph::PostProcessResourceDispatcher& mPostProcessResourceDispatcher;
126   DiscardQueue&            mDiscardQueue; ///< Unwanted resources are added here during UpdateCache()
127   RenderQueue&             mRenderQueue;
128   unsigned int             mNotificationCount;
129   bool                     cacheUpdated; ///< returned by UpdateCache(). Set true in NotifyTickets to indicate a change in a resource
130
131   /**
132    * These containers are used to processs requests, and ResourceCache callbacks.
133    * The live request containers are simply sets of integer resource ids.
134    * The ID of a new request will be placed in the loading container.
135    * If the Ticket is destroyed during the load, the ID will be removed.
136    * If the load fails, the ID will be moved to the failed container.
137    * When the Ticket is notified of the failure, the ID will be removed.
138    * If the load succeeds, the ID will be moved to the new-completed container.
139    * When the Ticket is notified of the completion, the ID will be moved to the old-completed container.
140    * If a Ticket is destroyed after a successful load, the ID will be moved to the dead container.
141    * When the resources are eventually deleted, the ID will be removed from the dead container.
142    */
143   LiveRequestContainer loadingRequests;
144   LiveRequestContainer newCompleteRequests;
145   LiveRequestContainer oldCompleteRequests;
146   LiveRequestContainer newFailedRequests;
147   LiveRequestContainer oldFailedRequests;
148   DeadRequestContainer deadRequests;
149   LiveRequestContainer saveRequests;          ///< copy of id's being saved (must also be in newCompleteRequests or oldCompleteRequests)
150   LiveRequestContainer completeSaveRequests;  ///< successful save ids are moved from saveRequests to here
151
152   /**
153    * This is the resource cache. It's filled/emptied from within Core::Update()
154    */
155   BitmapMetadataCache mBitmapMetadata;
156   MeshCache           mMeshes;
157   ShaderCache         mShaders;
158 };
159
160 ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
161                                   NotificationManager& notificationManager,
162                                   TextureCacheDispatcher& textureCacheDispatcher,
163                                   ResourcePostProcessList& resourcePostProcessQueue,
164                                   SceneGraph::PostProcessResourceDispatcher& postProcessResourceDispatcher,
165                                   DiscardQueue& discardQueue,
166                                   RenderQueue& renderQueue )
167 {
168   mImpl = new ResourceManagerImpl( platformAbstraction,
169                                    notificationManager,
170                                    textureCacheDispatcher,
171                                    resourcePostProcessQueue,
172                                    postProcessResourceDispatcher,
173                                    discardQueue,
174                                    renderQueue );
175 }
176
177 ResourceManager::~ResourceManager()
178 {
179   delete mImpl;
180 }
181
182 /********************************************************************************
183  ************************ ResourceClient direct interface  **********************
184  ********************************************************************************/
185
186 void ResourceManager::SetClient( ResourceClient& client )
187 {
188   mImpl->mResourceClient = &client;
189 }
190
191 /********************************************************************************
192  ************************ UpdateManager direct interface  ***********************
193  ********************************************************************************/
194
195 bool ResourceManager::UpdateCache( BufferIndex updateBufferIndex )
196 {
197   DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: UpdateCache(bufferIndex:%u)\n", updateBufferIndex);
198
199   // 1) Move unwanted resources to the DiscardQueue
200
201   DiscardDeadResources( updateBufferIndex );
202
203   // 2) Fill the resource cache
204   mImpl->cacheUpdated = false;
205
206   mImpl->mPlatformAbstraction.GetResources(*this);
207
208   return mImpl->cacheUpdated;
209 }
210
211 void ResourceManager::PostProcessResources( BufferIndex updateBufferIndex )
212 {
213   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
214   DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "ResourceManager: PostProcessResources()\n");
215
216   unsigned int numIds = mImpl->mResourcePostProcessQueue[ updateBufferIndex ].size();
217   unsigned int i;
218
219   // process the list where RenderManager put post process requests
220   for (i = 0; i < numIds; ++i)
221   {
222     ResourcePostProcessRequest ppRequest = mImpl->mResourcePostProcessQueue[ updateBufferIndex ][i];
223     switch(ppRequest.postProcess)
224     {
225       case ResourcePostProcessRequest::UPLOADED:
226       {
227         SendToClient( UploadedMessage( *mImpl->mResourceClient, ppRequest.id ) );
228         break;
229       }
230       case ResourcePostProcessRequest::SAVE:
231       {
232         SendToClient( SaveResourceMessage( *mImpl->mResourceClient, ppRequest.id ) );
233         break;
234
235       }
236       case ResourcePostProcessRequest::DELETED:
237       {
238         // TextureObservers handled in TextureCache
239         break;
240       }
241     }
242   }
243
244   mImpl->mResourcePostProcessQueue[ updateBufferIndex ].clear();
245 }
246
247
248 /********************************************************************************
249  *************************** CoreImpl direct interface  *************************
250  ********************************************************************************/
251
252 bool ResourceManager::ResourcesToProcess()
253 {
254   bool workTodo = false;
255
256   // need to make sure we have passed all the notifications to the event handling side
257   workTodo |= !mImpl->newCompleteRequests.empty();
258   workTodo |= !mImpl->newFailedRequests.empty();
259   // check if there's something still loading
260   workTodo |= !mImpl->loadingRequests.empty();
261   workTodo |= !mImpl->saveRequests.empty();
262
263   return workTodo;
264 }
265
266
267 /********************************************************************************
268  ********************************* Message handlers *****************************
269  ********************************************************************************/
270
271 void ResourceManager::HandleLoadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority )
272 {
273   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
275   // Add ID to the loading set
276   mImpl->loadingRequests.insert(id);
277
278   // Make the load request last
279   mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
280 }
281
282 void ResourceManager::HandleDecodeResourceRequest(
283   ResourceId id,
284   const ResourceTypePath& typePath,
285   RequestBufferPtr buffer,
286   Integration::LoadResourcePriority priority )
287 {
288   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);
289
290   // Add ID to the loading set
291   mImpl->loadingRequests.insert(id);
292
293   // Make the load request, stuffing the buffer of encoded bytes into the same field used when saving resources:
294   mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, "", buffer, priority));
295 }
296
297 void ResourceManager::HandleAddBitmapImageRequest( ResourceId id, BitmapPtr bitmap )
298 {
299   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
300   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddBitmapImageRequest(id:%u)\n", id);
301
302   mImpl->oldCompleteRequests.insert(id);
303   mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New( bitmap.Get() )));
304   mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap.Get() );
305 }
306
307 void ResourceManager::HandleAddNativeImageRequest(ResourceId id, NativeImageInterfacePtr nativeImage)
308 {
309   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
310   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddNativeImageRequest(id:%u)\n", id);
311
312   mImpl->oldCompleteRequests.insert(id);
313
314   mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImage)));
315   mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImage );
316 }
317
318 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
319 {
320   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
321   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
322
323   mImpl->oldCompleteRequests.insert(id);
324
325   BitmapMetadata bitmapMetadata = BitmapMetadata::New(width, height, Pixel::HasAlpha(pixelFormat));
326   bitmapMetadata.SetIsFramebuffer(true);
327   mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
328
329   mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, width, height, pixelFormat );
330 }
331
332 void ResourceManager::HandleAddFrameBufferImageRequest( ResourceId id, NativeImageInterfacePtr nativeImage )
333 {
334   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
335   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAddFrameBufferImageRequest(id:%u)\n", id);
336
337   mImpl->oldCompleteRequests.insert(id);
338
339   BitmapMetadata bitmapMetadata = BitmapMetadata::New(nativeImage);
340   bitmapMetadata.SetIsNativeImage(true);
341   bitmapMetadata.SetIsFramebuffer(true);
342   mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, bitmapMetadata));
343
344   mImpl->mTextureCacheDispatcher.DispatchCreateTextureForFrameBuffer( id, nativeImage );
345 }
346
347 void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
348 {
349   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateTextureRequest(id:%u)\n", id);
350
351   mImpl->oldCompleteRequests.insert(id);
352   mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ );
353 }
354
355 void ResourceManager::HandleAllocateMeshRequest( ResourceId id, MeshData* meshData )
356 {
357   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleAllocateMeshRequest(id:%u)\n", id);
358
359   SceneGraph::Mesh* renderableMesh(SceneGraph::Mesh::New(id, mImpl->mPostProcessResourceDispatcher, mImpl->mRenderQueue, meshData));
360
361   DALI_ASSERT_ALWAYS(renderableMesh && "renderableMesh not created");
362
363   // Add the ID to the completed set, and store the resource
364   mImpl->newCompleteRequests.insert(id);
365   mImpl->mMeshes.insert(MeshDataPair(id, renderableMesh));
366
367   // Let NotificationManager know that the resource manager needs to do some processing
368   NotifyTickets();
369 }
370
371 void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath )
372 {
373   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
374
375   const ShaderResourceType* shaderType = dynamic_cast<const ShaderResourceType*>(typePath.type);
376   DALI_ASSERT_DEBUG(shaderType);
377
378   if( shaderType )
379   {
380     ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader));
381
382     mImpl->mPlatformAbstraction.LoadShaderBinFile(typePath.path, shaderData->GetBuffer());
383
384     // Add the ID to the completed set
385     mImpl->newCompleteRequests.insert(id);
386
387     // Cache the resource
388     mImpl->mShaders.insert(ShaderDataPair(id, shaderData));
389
390     // Let NotificationManager know that the resource manager needs to do some processing
391     NotifyTickets();
392   }
393 }
394
395 void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area )
396 {
397   if( textureId )
398   {
399     mImpl->mTextureCacheDispatcher.DispatchUpdateTextureArea( textureId, area );
400   }
401 }
402
403 void ResourceManager::HandleUploadBitmapRequest( ResourceId destId, Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset )
404 {
405   if( destId && bitmap )
406   {
407     mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( destId, bitmap, xOffset, yOffset );
408   }
409 }
410
411 void ResourceManager::HandleUploadBitmapRequest( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
412 {
413   if( destId && srcId )
414   {
415     mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( destId, srcId, xOffset, yOffset );
416   }
417 }
418
419 void ResourceManager::HandleUpdateMeshRequest( BufferIndex updateBufferIndex, ResourceId id, MeshData* meshData )
420 {
421   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
422   SceneGraph::Mesh* mesh = GetMesh( id );
423   DALI_ASSERT_DEBUG(mesh);
424
425   // Update the mesh data
426   mesh->SetMeshData( meshData );
427
428   // Update the GL buffers in the next Render
429   typedef MessageDoubleBuffered2< SceneGraph::Mesh, SceneGraph::Mesh::ThreadBuffer, OwnerPointer<MeshData> > DerivedType;
430
431   // Reserve some memory inside the render queue
432   unsigned int* slot = mImpl->mRenderQueue.ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
433
434   // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
435   new (slot) DerivedType( mesh, &SceneGraph::Mesh::MeshDataUpdated, SceneGraph::Mesh::RENDER_THREAD, meshData );
436 }
437
438 void ResourceManager::HandleReloadResourceRequest( ResourceId id, const ResourceTypePath& typePath, LoadResourcePriority priority, bool resetFinishedStatus )
439 {
440   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
441   DALI_LOG_INFO( Debug::Filter::gResource, Debug::General, "ResourceManager: HandleReloadRequest(id:%u, path:%s)\n", id, typePath.path.c_str() );
442
443   bool resourceIsAlreadyLoading = true;
444
445   if( resetFinishedStatus )
446   {
447     if( ! RemoveId( mImpl->newCompleteRequests, id ) )
448     {
449       RemoveId( mImpl->oldCompleteRequests, id );
450     }
451   }
452
453   // ID might be in the loading set
454   LiveRequestIter iter = mImpl->loadingRequests.find( id );
455   if ( iter == mImpl->loadingRequests.end() )
456   {
457     // Add ID to the loading set
458     mImpl->loadingRequests.insert(id);
459     resourceIsAlreadyLoading = false;
460   }
461
462   if ( !resourceIsAlreadyLoading )
463   {
464     // load resource again
465     mImpl->mPlatformAbstraction.LoadResource(ResourceRequest(id, *typePath.type, typePath.path, priority));
466     SendToClient( LoadingMessage( *mImpl->mResourceClient, id ) );
467   }
468 }
469
470 void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTypePath& typePath )
471 {
472   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleSaveResourceRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
473
474   bool resourceFound = false;
475
476   // ID must be in the complete sets
477   LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
478   if (iter != mImpl->newCompleteRequests.end())
479   {
480     resourceFound = true;
481   }
482   else
483   {
484     LiveRequestIter iter = mImpl->oldCompleteRequests.find(id);
485     if (iter != mImpl->oldCompleteRequests.end())
486     {
487       resourceFound = true;
488     }
489   }
490
491   if( resourceFound )
492   {
493     ResourcePointer resource;
494     DALI_ASSERT_DEBUG( typePath.type != NULL );
495
496     switch( typePath.type->id )
497     {
498       case ResourceBitmap:
499       {
500         break;
501       }
502       case ResourceNativeImage:
503       {
504         break;
505       }
506       case ResourceTargetImage:
507       {
508         break;
509       }
510       case ResourceShader:
511       {
512         resource = GetShaderData(id);
513         break;
514       }
515       case ResourceMesh:
516       {
517         break;
518       }
519     }
520
521     if( resource ) // i.e. if it's a saveable resource
522     {
523       mImpl->saveRequests.insert(id);
524
525       ResourceRequest request(id, *typePath.type, typePath.path, resource);
526       mImpl->mPlatformAbstraction.SaveResource(request);
527     }
528   }
529 }
530
531 void ResourceManager::HandleDiscardResourceRequest( ResourceId deadId, ResourceTypeId typeId )
532 {
533   bool wasComplete = false;
534   bool wasLoading = false;
535
536   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleDiscardResourceRequest(id:%u)\n", deadId);
537
538   // remove copies of the deadId from completed/failed saving sets
539   RemoveId(mImpl->completeSaveRequests, deadId);
540
541   // Search for the ID in one of the live containers
542   // IDs are only briefly held in the new-completed or failed containers; check those last
543   // Try removing from the old-completed requests
544   bool foundLiveRequest = wasComplete = RemoveId(mImpl->oldCompleteRequests, deadId);
545
546   // Try removing from the loading requests
547   if (!foundLiveRequest)
548   {
549     foundLiveRequest = wasLoading = RemoveId(mImpl->loadingRequests, deadId);
550   }
551
552   // Try removing from the new completed requests
553   if (!foundLiveRequest)
554   {
555     foundLiveRequest = wasComplete = RemoveId(mImpl->newCompleteRequests, deadId);
556   }
557
558   // Try removing from the new failed requests
559   if (!foundLiveRequest)
560   {
561     foundLiveRequest = RemoveId(mImpl->newFailedRequests, deadId);
562   }
563
564   // Try removing from the old failed requests
565   if (!foundLiveRequest)
566   {
567     foundLiveRequest = RemoveId(mImpl->oldFailedRequests, deadId);
568   }
569
570   // ID should be in one of the live sets
571   if (!foundLiveRequest)
572   {
573     DALI_LOG_WARNING("HandleDiscardResourceRequest: ID should be in one of the live sets!\n");
574   }
575   DALI_ASSERT_DEBUG(foundLiveRequest);
576
577   if (wasComplete)
578   {
579     if(typeId == ResourceBitmap ||
580        typeId == ResourceNativeImage ||
581        typeId == ResourceTargetImage )
582     {
583        // remove the meta data
584       mImpl->mBitmapMetadata.erase( deadId );
585
586       // destroy the texture
587       mImpl->mTextureCacheDispatcher.DispatchDiscardTexture( deadId );
588     }
589     else
590     {
591       // Move ID from completed to dead set
592       mImpl->deadRequests.insert(DeadRequestPair(deadId, typeId));
593     }
594   }
595
596   if (wasLoading)
597   {
598     mImpl->mPlatformAbstraction.CancelLoad(deadId, typeId);
599   }
600 }
601
602 void ResourceManager::HandleCreateGlTextureRequest(ResourceId id)
603 {
604   mImpl->mTextureCacheDispatcher.DispatchCreateGlTexture( id );
605 }
606
607 /********************************************************************************
608  ******************** Update thread object direct interface  ********************
609  ********************************************************************************/
610
611 bool ResourceManager::IsResourceLoaded(ResourceId id)
612 {
613   bool loaded = false;
614
615   if( id > 0 )
616   {
617     LiveRequestIter iter = mImpl->newCompleteRequests.find(id);
618     if( iter != mImpl->newCompleteRequests.end() )
619     {
620       loaded = true;
621     }
622     else
623     {
624       iter = mImpl->oldCompleteRequests.find(id);
625       if( iter != mImpl->oldCompleteRequests.end() )
626       {
627         loaded = true;
628       }
629     }
630   }
631
632   return loaded;
633 }
634
635 bool ResourceManager::IsResourceLoadFailed(ResourceId id)
636 {
637   bool loadFailed = false;
638
639   if( id > 0 )
640   {
641     LiveRequestIter iter = mImpl->newFailedRequests.find(id);
642     if( iter != mImpl->newFailedRequests.end() )
643     {
644       loadFailed = true;
645     }
646     else
647     {
648       iter = mImpl->oldFailedRequests.find(id);
649       if( iter != mImpl->oldFailedRequests.end() )
650       {
651         loadFailed = true;
652       }
653     }
654   }
655
656   return loadFailed;
657 }
658
659 BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id)
660 {
661   BitmapMetadata metadata;
662
663   if( id > 0 )
664   {
665     BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
666     if( iter != mImpl->mBitmapMetadata.end() )
667     {
668       metadata = iter->second;
669     }
670   }
671
672   return metadata;
673 }
674
675 Internal::SceneGraph::Mesh* ResourceManager::GetMesh(ResourceId id)
676 {
677   SceneGraph::Mesh* mesh = NULL;
678   MeshCacheIter iter = mImpl->mMeshes.find(id);
679
680   if (iter != mImpl->mMeshes.end())
681   {
682     mesh = iter->second;
683   }
684
685   return mesh;
686 }
687
688 ShaderDataPtr ResourceManager::GetShaderData(ResourceId id)
689 {
690   ShaderDataPtr shaderData;
691   ShaderCacheIter iter = mImpl->mShaders.find(id);
692   if(iter != mImpl->mShaders.end())
693   {
694     shaderData = iter->second;
695   }
696   return shaderData;
697 }
698
699 /********************************************************************************
700  ************************* ResourceCache Implementation  ************************
701  ********************************************************************************/
702
703 void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, ResourcePointer resource, LoadStatus loadStatus )
704 {
705   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
706   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");
707
708   // ID might be in the loading set
709   LiveRequestIter iter = mImpl->loadingRequests.find(id);
710
711   if ( iter != mImpl->loadingRequests.end() )
712   {
713     if( loadStatus == RESOURCE_COMPLETELY_LOADED )
714     {
715       // Remove from the loading set
716       mImpl->loadingRequests.erase(iter);
717
718       // Add the ID to the new-completed set, and store the resource
719       mImpl->newCompleteRequests.insert(id);
720     }
721
722     switch ( type )
723     {
724       case ResourceBitmap:
725       {
726         DALI_ASSERT_DEBUG( loadStatus == RESOURCE_COMPLETELY_LOADED && "Partial results not handled for image loading.\n" );
727         Bitmap* const bitmap = static_cast<Bitmap*>( resource.Get() );
728         if( !bitmap )
729         {
730           DALI_LOG_ERROR( "Missing bitmap in loaded resource with id %u.\n", id );
731           break;
732         }
733         unsigned int bitmapWidth  = bitmap->GetImageWidth();
734         unsigned int bitmapHeight = bitmap->GetImageHeight();
735
736         if( Bitmap::PackedPixelsProfile * packedBitmap = bitmap->GetPackedPixelsProfile() )
737         {
738           bitmapWidth  = packedBitmap->GetBufferWidth();
739           bitmapHeight = packedBitmap->GetBufferHeight();
740         }
741         ImageAttributes attrs = ImageAttributes::New( bitmapWidth, bitmapHeight ); ///!< Issue #AHC01
742         UpdateImageTicket (id, attrs);
743
744         // Check for reloaded bitmap
745         BitmapMetadataIter iter = mImpl->mBitmapMetadata.find(id);
746         if (iter != mImpl->mBitmapMetadata.end())
747         {
748           iter->second.Update(bitmap);
749           mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( id, bitmap );
750         }
751         else
752         {
753           mImpl->mTextureCacheDispatcher.DispatchCreateTextureForBitmap( id, bitmap );
754           mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(bitmap)));
755         }
756
757         break;
758       }
759
760       case ResourceNativeImage:
761       {
762         NativeImageInterfacePtr nativeImg( static_cast<NativeImageInterface*>(resource.Get()) );
763
764         ImageAttributes attrs = ImageAttributes::New(nativeImg->GetWidth(), nativeImg->GetHeight());
765
766         mImpl->mBitmapMetadata.insert(BitmapMetadataPair(id, BitmapMetadata::New(nativeImg)));
767         mImpl->mTextureCacheDispatcher.DispatchCreateTextureForNativeImage( id, nativeImg );
768
769         UpdateImageTicket (id, attrs);
770         break;
771       }
772
773       case ResourceTargetImage:
774       {
775         break;
776       }
777
778       case ResourceShader:
779       {
780         mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
781         break;
782       }
783
784       case ResourceMesh:
785       {
786         break;
787       }
788     }
789
790     // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
791     NotifyTickets();
792
793     // flag that a load has completed and the cache updated
794     mImpl->cacheUpdated = true;
795   }
796   else
797   {
798     // This warning can fire if a cancelled load is forgotten here while already complete on a resource thread:
799     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");
800   }
801 }
802
803 void ResourceManager::SaveComplete(ResourceId id, ResourceTypeId type)
804 {
805   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
806   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveComplete(id:%u)\n", id);
807
808   // ID must be in the saving set
809   LiveRequestIter iter = mImpl->saveRequests.find(id);
810
811   if (iter != mImpl->saveRequests.end())
812   {
813     // Remove from the saving set
814     mImpl->saveRequests.erase(iter);
815
816     // If resource has not been discarded..
817     if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
818     {
819       SendToClient( SavingSucceededMessage( *mImpl->mResourceClient, id ) );
820     }
821
822     mImpl->cacheUpdated = true;
823   }
824 }
825
826 void ResourceManager::LoadFailed(ResourceId id, ResourceFailure failure)
827 {
828   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: LoadFailed(id:%u)\n", id);
829
830   // ID might be in the loading set
831   LiveRequestIter iter = mImpl->loadingRequests.find(id);
832
833   if (iter != mImpl->loadingRequests.end())
834   {
835     // Remove from the loading set
836     mImpl->loadingRequests.erase(iter);
837
838     // Add the ID to the failed set, this will trigger a notification during UpdateTickets
839     mImpl->newFailedRequests.insert(id);
840
841     // Let NotificationManager know that the resource manager needs to do some processing
842     NotifyTickets();
843
844     mImpl->cacheUpdated = true;
845   }
846 }
847
848 void ResourceManager::SaveFailed(ResourceId id, ResourceFailure failure)
849 {
850   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
851   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: SaveFailed(id:%u)\n", id);
852
853   // ID must be in the saving set
854   LiveRequestIter iter = mImpl->saveRequests.find(id);
855
856   if (iter != mImpl->saveRequests.end())
857   {
858     // Remove from the saving set
859     mImpl->saveRequests.erase(iter);
860
861     // If resource has not been discarded..
862
863     if( mImpl->deadRequests.find(id) == mImpl->deadRequests.end() )
864     {
865       SendToClient( SavingFailedMessage( *mImpl->mResourceClient, id ) );
866     }
867
868     mImpl->cacheUpdated = true;
869   }
870 }
871
872 /********************************************************************************
873  ********************************* Private Methods  *****************************
874  ********************************************************************************/
875
876 void ResourceManager::NotifyTickets()
877 {
878   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
879   // Success notifications
880   for (LiveRequestIter iter = mImpl->newCompleteRequests.begin(); iter != mImpl->newCompleteRequests.end(); ++iter)
881   {
882     // Move to oldCompleteRequests
883     mImpl->oldCompleteRequests.insert(*iter);
884
885     SendToClient( LoadingSucceededMessage( *mImpl->mResourceClient, *iter ) );
886   }
887   mImpl->newCompleteRequests.clear();
888
889   // Failure notifications
890   for (LiveRequestIter iter = mImpl->newFailedRequests.begin(); iter != mImpl->newFailedRequests.end(); ++iter)
891   {
892     // Move to oldFailedRequests
893     mImpl->oldFailedRequests.insert(*iter);
894
895     // We should have a matching request ticket
896     SendToClient( LoadingFailedMessage( *mImpl->mResourceClient, *iter ) );
897   }
898   mImpl->newFailedRequests.clear();
899 }
900
901 void ResourceManager::UpdateImageTicket( ResourceId id, ImageAttributes& attributes ) ///!< Issue #AHC01
902 {
903   DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL );
904   // ResourceLoader should load images considering the requested size
905   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: UpdateImageTicket(id:%u)\n", id);
906
907   // Let NotificationManager know that the resource manager needs to do some processing
908   SendToClient( UpdateImageTicketMessage( *mImpl->mResourceClient, id, attributes) );
909 }
910
911 void ResourceManager::SendToClient( MessageBase* message )
912 {
913   mImpl->mNotificationManager.QueueMessage( message );
914 }
915
916 void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex )
917 {
918   for (DeadRequestIter iter = mImpl->deadRequests.begin(); iter != mImpl->deadRequests.end(); )
919   {
920     // Delay destroying ids in saveRequests
921     if( mImpl->saveRequests.find(iter->first) != mImpl->saveRequests.end())
922     {
923       ++iter;
924       continue;
925     }
926
927     /**
928      * We should find a resource of the correct type, and move it to the DiscardQueue.
929      */
930     switch (iter->second)
931     {
932       case ResourceBitmap:
933       case ResourceNativeImage:
934       case ResourceTargetImage:
935         break;
936
937       case ResourceMesh:
938       {
939         MeshCacheIter mesh = mImpl->mMeshes.find(iter->first);
940         DALI_ASSERT_DEBUG( mImpl->mMeshes.end() != mesh );
941         if( mImpl->mMeshes.end() != mesh )
942         {
943           mImpl->mDiscardQueue.Add( updateBufferIndex, mesh->second );
944           mImpl->mMeshes.erase( mesh );
945         }
946       }
947       break;
948
949       case ResourceShader:
950       {
951         ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first);
952         DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
953         // shader data is owned through intrusive pointers so no need for discard queue
954         mImpl->mShaders.erase( shaderIter );
955         break;
956       }
957     }
958
959     // Erase the item and increment the iterator
960     mImpl->deadRequests.erase(iter++);
961   }
962 }
963
964 } // namespace Internal
965
966 } // namespace Dali