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