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