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