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