2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/resources/resource-client.h>
20 #include <dali/public-api/common/map-wrapper.h>
22 #include <dali/integration-api/glyph-set.h>
23 #include <dali/integration-api/resource-request.h>
24 #include <dali/integration-api/debug.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/event/text/resource/glyph-load-observer.h>
28 #include <dali/internal/event/images/image-impl.h>
29 #include <dali/internal/update/resources/resource-manager.h>
30 #include <dali/internal/update/manager/update-manager.h>
37 using namespace Dali::Integration;
39 typedef std::map<ResourceId, ResourceTicket*> TicketContainer;
40 typedef TicketContainer::iterator TicketContainerIter;
41 typedef TicketContainer::size_type TicketContainerSize;
42 typedef std::pair<ResourceId, ResourceTicket*> TicketPair;
44 typedef std::map<ResourceId, Bitmap*> BitmapCache;
45 typedef BitmapCache::iterator BitmapCacheIter;
47 struct ResourceClient::Impl
49 Impl(ResourcePolicy::DataRetention dataRetentionPolicy)
51 mGlyphLoadObserver(NULL),
52 mDataRetentionPolicy( dataRetentionPolicy )
57 TicketContainer mTickets;
59 GlyphLoadObserver* mGlyphLoadObserver;
60 ResourcePolicy::DataRetention mDataRetentionPolicy;
63 ResourceClient::ResourceClient( ResourceManager& resourceManager,
64 SceneGraph::UpdateManager& updateManager,
65 ResourcePolicy::DataRetention dataRetentionPolicy)
66 : mResourceManager(resourceManager),
67 mUpdateManager(updateManager)
69 mImpl = new ResourceClient::Impl(dataRetentionPolicy);
70 mResourceManager.SetClient(*this);
73 ResourceClient::~ResourceClient()
75 // Guard to allow handle destruction after Core has been destroyed
76 if ( Stage::IsInstalled() )
78 for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
80 (*iter).second->StopLifetimeObservation();
86 ResourcePolicy::DataRetention ResourceClient::GetResourceDataRetentionPolicy()
88 return mImpl->mDataRetentionPolicy;
91 ResourceTicketPtr ResourceClient::RequestResource(
92 const ResourceType& type,
93 const std::string& path,
94 LoadResourcePriority priority )
96 ResourceTicketPtr newTicket;
97 ResourceTypePath typePath(type, path);
100 // Create the ticket first
101 // NOTE: pre-increment, otherwise we get 0 for first one.
102 newId = ++(mImpl->mNextId);
108 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
109 // image tickets will cache the requested parameters, which are updated on successful loading
110 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
111 imageTicket->mAttributes = bitmapResource.imageAttributes;
112 newTicket = imageTicket;
116 case ResourceNativeImage:
118 const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
119 // image tickets will cache the requested parameters, which are updated on successful loading
120 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
121 imageTicket->mAttributes = nativeResource.imageAttributes;
122 newTicket = imageTicket;
125 case ResourceModel: // FALLTHROUGH
126 case ResourceTargetImage:
131 newTicket = new ResourceTicket(*this, newId, typePath);
136 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
138 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
140 RequestLoadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, priority );
144 ResourceTicketPtr ResourceClient::DecodeResource(
145 const ResourceType& type,
146 RequestBufferPtr buffer,
147 LoadResourcePriority priority )
149 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" );
150 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
151 ResourceTicketPtr newTicket;
152 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
154 ResourceTypePath typePath( type, "" );
155 ResourceId newId = 0;
157 // Create the correct ticket type for the resource:
162 // NOTE: pre-increment, otherwise we get 0 for first one.
163 newId = ++(mImpl->mNextId);
164 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
165 // Image tickets will cache the requested parameters, which are updated on successful loading
166 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
167 imageTicket->mAttributes = bitmapResource.imageAttributes;
168 newTicket = imageTicket;
173 case ResourceNativeImage:
175 case ResourceTargetImage:
180 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
186 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
187 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
189 RequestDecodeResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, buffer, priority );
195 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
196 const std::string& path )
198 ResourceTicketPtr newTicket;
200 const ResourceId newId = ++(mImpl->mNextId);
202 ResourceTypePath typePath(type, path);
203 newTicket = new ResourceTicket(*this, newId, typePath);
205 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
207 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
209 RequestLoadShaderMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath );
213 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
215 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
217 bool resourceExists = false;
218 TicketContainerIter ticketIter;
219 ticketIter = mImpl->mTickets.find(id);
221 if(ticketIter != mImpl->mTickets.end())
223 resourceExists = true;
224 // The ticket is already being observed
225 ResourceTicket* ticket = ticketIter->second;
226 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
227 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
228 DALI_ASSERT_DEBUG( typePathPtr );
229 RequestReloadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
233 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
235 return resourceExists;
238 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
240 DALI_ASSERT_DEBUG( ticket );
242 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
244 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
247 if( 0 != url.length() )
249 ResourceTypePath typePath( *(typePathPtr->type), url );
250 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
254 ResourceTypePath typePath( *typePathPtr );
255 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
260 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
262 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
264 ResourceTicketPtr ticket;
266 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
268 if ( mImpl->mTickets.end() != ticketIter )
270 ticket = ticketIter->second;
276 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
278 unsigned int bufferWidth,
279 unsigned int bufferHeight,
280 Pixel::Format pixelformat )
282 /* buffer is available via public-api, therefore not discardable */
283 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
284 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
285 DALI_ASSERT_DEBUG(packedBitmap);
287 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
288 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
289 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
291 ImageTicketPtr ticket = AddBitmapImage(bitmap);
293 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
294 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
298 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
300 DALI_ASSERT_DEBUG( bitmap != NULL );
302 ImageTicketPtr newTicket;
304 const ResourceId newId = ++(mImpl->mNextId);
306 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
307 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
308 ResourceTypePath typePath(bitmapResourceType, "");
309 newTicket = new ImageTicket(*this, newId, typePath);
310 newTicket->mAttributes = imageAttributes;
311 newTicket->LoadingSucceeded();
313 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
315 // Store bitmap for immediate access.
316 mImpl->mBitmaps[newId] = bitmap;
318 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
319 RequestAddBitmapImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, bitmap );
324 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
326 ImageTicketPtr newTicket;
328 const ResourceId newId = ++(mImpl->mNextId);
329 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
330 ResourceTypePath typePath(nativeImageResourceType, "");
331 newTicket = new ImageTicket(*this, newId, typePath);
332 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
333 resourceData.GetHeight());
334 newTicket->LoadingSucceeded();
336 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
338 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
340 RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
345 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
347 ImageTicketPtr newTicket;
349 const ResourceId newId = ++(mImpl->mNextId);
351 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height);
352 RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
353 ResourceTypePath typePath(renderTargetResourceType, "");
354 newTicket = new ImageTicket(*this, newId, typePath);
355 newTicket->mAttributes = imageAttributes;
356 newTicket->LoadingSucceeded();
358 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
360 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
361 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
366 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
368 ImageTicketPtr newTicket;
370 const ResourceId newId = ++(mImpl->mNextId);
372 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight() );
373 RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
374 ResourceTypePath typePath(renderTargetResourceType, "");
375 newTicket = new ImageTicket(*this, newId, typePath);
376 newTicket->mAttributes = imageAttributes;
377 newTicket->LoadingSucceeded();
379 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
381 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
382 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
388 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
390 Pixel::Format pixelformat )
392 ImageTicketPtr newTicket;
393 const ResourceId newId = ++(mImpl->mNextId);
395 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height);
396 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
397 ResourceTypePath typePath(bitmapResourceType, "");
398 newTicket = new ImageTicket(*this, newId, typePath);
400 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
401 newTicket->mAttributes = imageAttributes;
402 newTicket->LoadingSucceeded();
404 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
406 RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
411 void ResourceClient::UpdateTexture( ResourceId id,
412 BitmapUploadArray uploadArray )
414 RequestUpdateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, uploadArray );
417 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
419 ResourceTicketPtr newTicket;
420 const ResourceId newId = ++(mImpl->mNextId);
421 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
422 ResourceTypePath typePath(meshResourceType, "");
423 newTicket = new ResourceTicket(*this, newId, typePath);
424 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
426 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
427 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
432 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
434 DALI_ASSERT_DEBUG( ticket );
436 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
439 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
441 RequestUploadBitmapMessage( mUpdateManager.GetEventToUpdate(),
449 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
451 DALI_ASSERT_DEBUG( ticket );
453 ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
454 if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
456 discardable = ResourcePolicy::DISCARD;
459 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
466 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
468 DALI_ASSERT_DEBUG( ticket );
470 Bitmap* bitmap = NULL;
471 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
473 if( iter != mImpl->mBitmaps.end() )
475 bitmap = iter->second;
480 void ResourceClient::SetGlyphLoadObserver( GlyphLoadObserver* glyphLoadedInterface )
482 mImpl->mGlyphLoadObserver = glyphLoadedInterface;
485 void ResourceClient::UpdateAtlasStatus( ResourceId id, ResourceId atlasId, Integration::LoadStatus loadStatus )
487 RequestAtlasUpdateMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, atlasId, loadStatus );
490 /********************************************************************************
491 ******************** ResourceTicketLifetimeObserver methods ****************
492 ********************************************************************************/
494 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
496 const ResourceId deadId = ticket.GetId();
497 const ResourceTypePath& typePath = ticket.GetTypePath();
499 // Ensure associated event owned resources are also removed
500 mImpl->mBitmaps.erase(ticket.GetId());
502 // The ticket object is dead, remove from tickets container
503 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
504 DALI_ASSERT_DEBUG(erased != 0);
505 (void)erased; // Avoid "unused variable erased" in release builds
507 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
508 RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
511 /********************************************************************************
512 *********************** Notifications from ResourceManager ******************
513 ********************************************************************************/
515 void ResourceClient::NotifyUploaded( ResourceId id )
517 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
519 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
520 if(ticketIter != mImpl->mTickets.end())
522 ResourceTicket* ticket = ticketIter->second;
527 void ResourceClient::NotifySaveRequested( ResourceId id )
529 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
531 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
532 if(ticketIter != mImpl->mTickets.end())
534 ResourceTicket* ticket = ticketIter->second;
535 SaveResource( ticket, "" );
540 void ResourceClient::NotifyLoading( ResourceId id )
542 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
544 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
545 if(ticketIter != mImpl->mTickets.end())
547 ResourceTicket* ticket = ticketIter->second;
552 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
554 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
556 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
557 if(ticketIter != mImpl->mTickets.end())
559 ResourceTicket* ticket = ticketIter->second;
560 ticket->LoadingSucceeded();
564 void ResourceClient::NotifyLoadingFailed( ResourceId id )
566 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
568 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
569 if(ticketIter != mImpl->mTickets.end())
571 ResourceTicket* ticket = ticketIter->second;
572 ticket->LoadingFailed();
576 void ResourceClient::NotifySavingSucceeded( ResourceId id )
578 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
580 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
581 if(ticketIter != mImpl->mTickets.end())
583 ResourceTicket* ticket = ticketIter->second;
584 ticket->SavingSucceeded();
588 void ResourceClient::NotifySavingFailed( ResourceId id )
590 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
592 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
593 if(ticketIter != mImpl->mTickets.end())
595 ResourceTicket* ticket = ticketIter->second;
596 ticket->SavingFailed();
600 void ResourceClient::NotifyGlyphSetLoaded( ResourceId id, const GlyphSet& glyphSet, LoadStatus loadStatus )
602 if( mImpl->mGlyphLoadObserver == NULL)
604 // should not happen.
605 DALI_ASSERT_DEBUG( !"GlyphLoadObserver == NULL ");
609 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyGlyphSetLoaded(hash:%u)\n", glyphSet.mFontHash);
611 mImpl->mGlyphLoadObserver->GlyphsLoaded( id, glyphSet, loadStatus );
614 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
616 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
618 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
619 if(ticketIter != mImpl->mTickets.end())
621 ResourceTicket* ticket = ticketIter->second;
622 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
625 imageTicket->mAttributes = imageAttributes;