2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
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.
18 #include <dali/internal/event/resources/resource-client.h>
19 #include <dali/public-api/common/map-wrapper.h>
21 #include <dali/integration-api/glyph-set.h>
22 #include <dali/integration-api/resource-request.h>
23 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/common/stage-impl.h>
26 #include <dali/internal/event/text/resource/glyph-load-observer.h>
27 #include <dali/internal/event/images/image-impl.h>
28 #include <dali/internal/update/resources/resource-manager.h>
29 #include <dali/internal/update/manager/update-manager.h>
36 using namespace Dali::Integration;
38 typedef std::map<ResourceId, ResourceTicket*> TicketContainer;
39 typedef TicketContainer::iterator TicketContainerIter;
40 typedef TicketContainer::size_type TicketContainerSize;
41 typedef std::pair<ResourceId, ResourceTicket*> TicketPair;
43 typedef std::map<ResourceId, Bitmap*> BitmapCache;
44 typedef BitmapCache::iterator BitmapCacheIter;
46 struct ResourceClient::Impl
50 mGlyphLoadObserver( NULL)
55 TicketContainer mTickets;
57 GlyphLoadObserver* mGlyphLoadObserver;
60 ResourceClient::ResourceClient( ResourceManager& resourceManager,
61 SceneGraph::UpdateManager& updateManager )
62 : mResourceManager(resourceManager),
63 mUpdateManager(updateManager)
65 mImpl = new ResourceClient::Impl();
66 mResourceManager.SetClient(*this);
69 ResourceClient::~ResourceClient()
71 // Guard to allow handle destruction after Core has been destroyed
72 if ( Stage::IsInstalled() )
74 for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
76 (*iter).second->StopLifetimeObservation();
82 ResourceTicketPtr ResourceClient::RequestResource(
83 const ResourceType& type,
84 const std::string& path,
85 LoadResourcePriority priority )
87 ResourceTicketPtr newTicket;
88 ResourceTypePath typePath(type, path);
91 // Create the ticket first
92 // NOTE: pre-increment, otherwise we get 0 for first one.
93 newId = ++(mImpl->mNextId);
99 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
100 // image tickets will cache the requested parameters, which are updated on successful loading
101 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
102 imageTicket->mAttributes = bitmapResource.imageAttributes;
103 newTicket = imageTicket;
107 case ResourceNativeImage:
109 const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
110 // image tickets will cache the requested parameters, which are updated on successful loading
111 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
112 imageTicket->mAttributes = nativeResource.imageAttributes;
113 newTicket = imageTicket;
116 case ResourceModel: // FALLTHROUGH
117 case ResourceTargetImage:
122 newTicket = new ResourceTicket(*this, newId, typePath);
127 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
129 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
131 RequestLoadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, priority );
135 ResourceTicketPtr ResourceClient::DecodeResource(
136 const ResourceType& type,
137 RequestBufferPtr buffer,
138 LoadResourcePriority priority )
140 DALI_ASSERT_DEBUG( type.id == ResourceBitmap && "Only bitmap resources are currently decoded from memory buffers. It should be easy to expand to other resource types though. The public API function at the front and the resource thread at the back end are all that should need to be changed. The code in the middle should be agnostic to the the resource type it is conveying.\n" );
141 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
142 ResourceTicketPtr newTicket;
143 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
145 ResourceTypePath typePath( type, "" );
146 ResourceId newId = 0;
148 // Create the correct ticket type for the resource:
153 // NOTE: pre-increment, otherwise we get 0 for first one.
154 newId = ++(mImpl->mNextId);
155 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
156 // Image tickets will cache the requested parameters, which are updated on successful loading
157 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
158 imageTicket->mAttributes = bitmapResource.imageAttributes;
159 newTicket = imageTicket;
164 case ResourceNativeImage:
166 case ResourceTargetImage:
171 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
177 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
178 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
180 RequestDecodeResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, buffer, priority );
186 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
187 const std::string& path )
189 ResourceTicketPtr newTicket;
191 const ResourceId newId = ++(mImpl->mNextId);
193 ResourceTypePath typePath(type, path);
194 newTicket = new ResourceTicket(*this, newId, typePath);
196 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
198 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
200 RequestLoadShaderMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath );
204 bool ResourceClient::ReloadResource( ResourceId id, LoadResourcePriority priority )
206 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
208 bool resourceExists = false;
209 TicketContainerIter ticketIter;
210 ticketIter = mImpl->mTickets.find(id);
212 if(ticketIter != mImpl->mTickets.end())
214 resourceExists = true;
215 // The ticket is already being observed
216 ResourceTicket* ticket = ticketIter->second;
217 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
218 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
219 DALI_ASSERT_DEBUG( typePathPtr );
220 RequestReloadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, *typePathPtr, priority );
224 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
226 return resourceExists;
229 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
231 DALI_ASSERT_DEBUG( ticket );
233 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
235 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
238 if( 0 != url.length() )
240 ResourceTypePath typePath( *(typePathPtr->type), url );
241 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
245 ResourceTypePath typePath( *typePathPtr );
246 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
251 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
253 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
255 ResourceTicketPtr ticket;
257 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
259 if ( mImpl->mTickets.end() != ticketIter )
261 ticket = ticketIter->second;
267 ImageTicketPtr ResourceClient::AllocateBitmapImage ( unsigned int width,
269 unsigned int bufferWidth,
270 unsigned int bufferHeight,
271 Pixel::Format pixelformat )
273 Bitmap * const bitmap = Bitmap::New(Bitmap::BITMAP_2D_PACKED_PIXELS, true); ///< Not exception safe.
274 Bitmap::PackedPixelsProfile * const packedBitmap = bitmap->GetPackedPixelsProfile();
275 DALI_ASSERT_DEBUG(packedBitmap);
277 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
278 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
279 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
281 ImageTicketPtr ticket = AddBitmapImage(bitmap);
283 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
284 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
288 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
290 DALI_ASSERT_DEBUG( bitmap != NULL );
292 ImageTicketPtr newTicket;
294 const ResourceId newId = ++(mImpl->mNextId);
296 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight(), bitmap->GetPixelFormat());
297 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
298 ResourceTypePath typePath(bitmapResourceType, "");
299 newTicket = new ImageTicket(*this, newId, typePath);
300 newTicket->mAttributes = imageAttributes;
301 newTicket->LoadingSucceeded();
303 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
305 // Store bitmap for immediate access.
306 mImpl->mBitmaps[newId] = bitmap;
308 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
309 RequestAddBitmapImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, bitmap );
314 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImage& resourceData )
316 ImageTicketPtr newTicket;
318 const ResourceId newId = ++(mImpl->mNextId);
319 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
320 ResourceTypePath typePath(nativeImageResourceType, "");
321 newTicket = new ImageTicket(*this, newId, typePath);
322 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
323 resourceData.GetHeight(),
324 resourceData.GetPixelFormat());
325 newTicket->LoadingSucceeded();
327 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
329 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
331 RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
336 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
338 ImageTicketPtr newTicket;
340 const ResourceId newId = ++(mImpl->mNextId);
342 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height, pixelFormat );
343 RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
344 ResourceTypePath typePath(renderTargetResourceType, "");
345 newTicket = new ImageTicket(*this, newId, typePath);
346 newTicket->mAttributes = imageAttributes;
347 newTicket->LoadingSucceeded();
349 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
351 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
352 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
357 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImage& nativeImage )
359 ImageTicketPtr newTicket;
361 const ResourceId newId = ++(mImpl->mNextId);
363 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight(), nativeImage.GetPixelFormat() );
364 RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
365 ResourceTypePath typePath(renderTargetResourceType, "");
366 newTicket = new ImageTicket(*this, newId, typePath);
367 newTicket->mAttributes = imageAttributes;
368 newTicket->LoadingSucceeded();
370 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
372 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
373 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
379 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
381 Pixel::Format pixelformat )
383 ImageTicketPtr newTicket;
384 const ResourceId newId = ++(mImpl->mNextId);
386 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height, pixelformat);
387 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
388 ResourceTypePath typePath(bitmapResourceType, "");
389 newTicket = new ImageTicket(*this, newId, typePath);
391 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
392 newTicket->mAttributes = imageAttributes;
393 newTicket->LoadingSucceeded();
395 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
397 RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
402 void ResourceClient::UpdateTexture( ResourceId id,
403 BitmapUploadArray uploadArray )
405 RequestUpdateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, uploadArray );
408 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
410 ResourceTicketPtr newTicket;
411 const ResourceId newId = ++(mImpl->mNextId);
412 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
413 ResourceTypePath typePath(meshResourceType, "");
414 newTicket = new ResourceTicket(*this, newId, typePath);
415 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
417 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
418 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
423 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
425 DALI_ASSERT_DEBUG( ticket );
427 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
430 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
432 DALI_ASSERT_DEBUG( ticket );
434 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
440 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
442 DALI_ASSERT_DEBUG( ticket );
444 Bitmap* bitmap = NULL;
445 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
447 if( iter != mImpl->mBitmaps.end() )
449 bitmap = iter->second;
454 void ResourceClient::SetGlyphLoadObserver( GlyphLoadObserver* glyphLoadedInterface )
456 mImpl->mGlyphLoadObserver = glyphLoadedInterface;
459 void ResourceClient::UpdateAtlasStatus( ResourceId id, ResourceId atlasId, Integration::LoadStatus loadStatus )
461 RequestAtlasUpdateMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, atlasId, loadStatus );
464 /********************************************************************************
465 ******************** ResourceTicketLifetimeObserver methods ****************
466 ********************************************************************************/
468 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
470 const ResourceId deadId = ticket.GetId();
471 const ResourceTypePath& typePath = ticket.GetTypePath();
473 // Ensure associated event owned resources are also removed
474 mImpl->mBitmaps.erase(ticket.GetId());
476 // The ticket object is dead, remove from tickets container
477 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
478 DALI_ASSERT_DEBUG(erased != 0);
479 (void)erased; // Avoid "unused variable erased" in release builds
481 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
482 RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
485 /********************************************************************************
486 *********************** Notifications from ResourceManager ******************
487 ********************************************************************************/
489 void ResourceClient::NotifyUploaded( ResourceId id )
491 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
493 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
494 if(ticketIter != mImpl->mTickets.end())
496 ResourceTicket* ticket = ticketIter->second;
501 void ResourceClient::NotifySaveRequested( ResourceId id )
503 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
505 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
506 if(ticketIter != mImpl->mTickets.end())
508 ResourceTicket* ticket = ticketIter->second;
509 SaveResource( ticket, "" );
514 void ResourceClient::NotifyLoading( ResourceId id )
516 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
518 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
519 if(ticketIter != mImpl->mTickets.end())
521 ResourceTicket* ticket = ticketIter->second;
526 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
528 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
530 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
531 if(ticketIter != mImpl->mTickets.end())
533 ResourceTicket* ticket = ticketIter->second;
534 ticket->LoadingSucceeded();
538 void ResourceClient::NotifyLoadingFailed( ResourceId id )
540 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
542 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
543 if(ticketIter != mImpl->mTickets.end())
545 ResourceTicket* ticket = ticketIter->second;
546 ticket->LoadingFailed();
550 void ResourceClient::NotifySavingSucceeded( ResourceId id )
552 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
554 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
555 if(ticketIter != mImpl->mTickets.end())
557 ResourceTicket* ticket = ticketIter->second;
558 ticket->SavingSucceeded();
562 void ResourceClient::NotifySavingFailed( ResourceId id )
564 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
566 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
567 if(ticketIter != mImpl->mTickets.end())
569 ResourceTicket* ticket = ticketIter->second;
570 ticket->SavingFailed();
574 void ResourceClient::NotifyGlyphSetLoaded( ResourceId id, const GlyphSet& glyphSet, LoadStatus loadStatus )
576 if( mImpl->mGlyphLoadObserver == NULL)
578 // should not happen.
579 DALI_ASSERT_DEBUG( !"GlyphLoadObserver == NULL ");
583 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyGlyphSetLoaded(hash:%u)\n", glyphSet.mFontHash);
585 mImpl->mGlyphLoadObserver->GlyphsLoaded( id, glyphSet, loadStatus );
588 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
590 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
592 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
593 if(ticketIter != mImpl->mTickets.end())
595 ResourceTicket* ticket = ticketIter->second;
596 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
599 imageTicket->mAttributes = imageAttributes;