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/resource-request.h>
23 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/common/event-thread-services.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/event/images/image-impl.h>
28 #include <dali/internal/update/resources/resource-manager.h>
35 using namespace Dali::Integration;
37 typedef std::map<ResourceId, ResourceTicket*> TicketContainer;
38 typedef TicketContainer::iterator TicketContainerIter;
39 typedef TicketContainer::size_type TicketContainerSize;
40 typedef std::pair<ResourceId, ResourceTicket*> TicketPair;
42 typedef std::map<ResourceId, Bitmap*> BitmapCache;
43 typedef BitmapCache::iterator BitmapCacheIter;
45 struct ResourceClient::Impl
47 Impl(ResourcePolicy::DataRetention dataRetentionPolicy)
49 mDataRetentionPolicy( dataRetentionPolicy )
54 TicketContainer mTickets;
56 ResourcePolicy::DataRetention mDataRetentionPolicy;
59 ResourceClient::ResourceClient( ResourceManager& resourceManager,
60 EventThreadServices& eventThreadServices,
61 ResourcePolicy::DataRetention dataRetentionPolicy)
62 : mResourceManager(resourceManager),
63 mEventThreadServices(eventThreadServices)
65 mImpl = new ResourceClient::Impl(dataRetentionPolicy);
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 ResourcePolicy::DataRetention ResourceClient::GetResourceDataRetentionPolicy()
84 return mImpl->mDataRetentionPolicy;
87 ResourceTicketPtr ResourceClient::RequestResource(
88 const ResourceType& type,
89 const std::string& path,
90 LoadResourcePriority priority )
92 ResourceTicketPtr newTicket;
93 ResourceTypePath typePath(type, path);
96 // Create the ticket first
97 // NOTE: pre-increment, otherwise we get 0 for first one.
98 newId = ++(mImpl->mNextId);
104 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
105 // image tickets will cache the requested parameters, which are updated on successful loading
106 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
107 imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );
108 newTicket = imageTicket;
112 case ResourceNativeImage:
114 const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
115 // image tickets will cache the requested parameters, which are updated on successful loading
116 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
117 imageTicket->mAttributes.SetSize( nativeResource.imageDimensions.GetWidth(), nativeResource.imageDimensions.GetHeight() );
118 newTicket = imageTicket;
121 case ResourceTargetImage:
125 newTicket = new ResourceTicket(*this, newId, typePath);
130 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
132 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
134 RequestLoadResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, priority );
138 ResourceTicketPtr ResourceClient::DecodeResource(
139 const ResourceType& type,
140 RequestBufferPtr buffer,
141 LoadResourcePriority priority )
143 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" );
144 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
145 ResourceTicketPtr newTicket;
146 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
148 ResourceTypePath typePath( type, "" );
149 ResourceId newId = 0;
151 // Create the correct ticket type for the resource:
156 // NOTE: pre-increment, otherwise we get 0 for first one.
157 newId = ++(mImpl->mNextId);
158 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
159 // Image tickets will cache the requested parameters, which are updated on successful loading
160 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
161 imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );;
162 newTicket = imageTicket;
167 case ResourceNativeImage:
168 case ResourceTargetImage:
172 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
178 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
179 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
181 RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
187 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
188 const std::string& path )
190 ResourceTicketPtr newTicket;
192 const ResourceId newId = ++(mImpl->mNextId);
194 ResourceTypePath typePath(type, path);
195 newTicket = new ResourceTicket(*this, newId, typePath);
197 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
199 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
201 RequestLoadShaderMessage( mEventThreadServices, mResourceManager, newId, typePath );
205 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
207 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
209 bool resourceExists = false;
210 TicketContainerIter ticketIter;
211 ticketIter = mImpl->mTickets.find(id);
213 if(ticketIter != mImpl->mTickets.end())
215 resourceExists = true;
216 // The ticket is already being observed
217 ResourceTicket* ticket = ticketIter->second;
218 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
219 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
220 DALI_ASSERT_DEBUG( typePathPtr );
221 RequestReloadResourceMessage( mEventThreadServices, mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
225 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
227 return resourceExists;
230 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
232 DALI_ASSERT_DEBUG( ticket );
234 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
236 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
239 if( 0 != url.length() )
241 ResourceTypePath typePath( *(typePathPtr->type), url );
242 RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
246 ResourceTypePath typePath( *typePathPtr );
247 RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
252 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
254 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
256 ResourceTicketPtr ticket;
258 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
260 if ( mImpl->mTickets.end() != ticketIter )
262 ticket = ticketIter->second;
268 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
270 unsigned int bufferWidth,
271 unsigned int bufferHeight,
272 Pixel::Format pixelformat )
274 /* buffer is available via public-api, therefore not discardable */
275 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
276 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
277 DALI_ASSERT_DEBUG(packedBitmap);
279 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
280 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
281 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
283 ImageTicketPtr ticket = AddBitmapImage(bitmap);
285 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
286 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
290 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
292 DALI_ASSERT_DEBUG( bitmap != NULL );
294 ImageTicketPtr newTicket;
296 const ResourceId newId = ++(mImpl->mNextId);
298 ImageAttributes imageAttributes = ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
299 BitmapResourceType bitmapResourceType( ImageDimensions::FromFloatVec2( imageAttributes.GetSize() ) ); // construct first as no copy ctor (needed to bind ref to object)
300 ResourceTypePath typePath(bitmapResourceType, "");
301 newTicket = new ImageTicket(*this, newId, typePath);
302 newTicket->mAttributes = imageAttributes;
303 newTicket->LoadingSucceeded();
305 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
307 // Store bitmap for immediate access.
308 mImpl->mBitmaps[newId] = bitmap;
310 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
311 RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
316 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
318 ImageTicketPtr newTicket;
320 const ResourceId newId = ++(mImpl->mNextId);
321 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
322 ResourceTypePath typePath(nativeImageResourceType, "");
323 newTicket = new ImageTicket(*this, newId, typePath);
324 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
325 resourceData.GetHeight());
326 newTicket->LoadingSucceeded();
328 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
330 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
332 RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
337 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
339 ImageTicketPtr newTicket;
341 const ResourceId newId = ++(mImpl->mNextId);
343 ImageAttributes imageAttributes = ImageAttributes::New(width, height);
344 RenderTargetResourceType renderTargetResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
345 ResourceTypePath typePath(renderTargetResourceType, "");
346 newTicket = new ImageTicket(*this, newId, typePath);
347 newTicket->mAttributes = imageAttributes;
348 newTicket->LoadingSucceeded();
350 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
352 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
353 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelFormat );
358 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
360 ImageTicketPtr newTicket;
362 const ResourceId newId = ++(mImpl->mNextId);
364 ImageAttributes imageAttributes = ImageAttributes::New( nativeImage.GetWidth(), nativeImage.GetHeight() );
365 RenderTargetResourceType renderTargetResourceType( ImageDimensions( nativeImage.GetWidth(), nativeImage.GetHeight() ) ); // construct first as no copy ctor (needed to bind ref to object)
366 ResourceTypePath typePath(renderTargetResourceType, "");
367 newTicket = new ImageTicket(*this, newId, typePath);
368 newTicket->mAttributes = imageAttributes;
369 newTicket->LoadingSucceeded();
371 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
373 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
374 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
380 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
382 Pixel::Format pixelformat )
384 ImageTicketPtr newTicket;
385 const ResourceId newId = ++(mImpl->mNextId);
387 ImageAttributes imageAttributes = ImageAttributes::New( width, height);
388 BitmapResourceType bitmapResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
389 ResourceTypePath typePath(bitmapResourceType, "");
390 newTicket = new ImageTicket(*this, newId, typePath);
392 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
393 newTicket->mAttributes = imageAttributes;
394 newTicket->LoadingSucceeded();
396 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
398 RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
403 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
405 ResourceTicketPtr newTicket;
406 const ResourceId newId = ++(mImpl->mNextId);
407 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
408 ResourceTypePath typePath(meshResourceType, "");
409 newTicket = new ResourceTicket(*this, newId, typePath);
410 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
412 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
413 RequestAllocateMeshMessage( mEventThreadServices, mResourceManager, newId, meshData );
418 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
420 DALI_ASSERT_DEBUG( ticket );
422 RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
425 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
427 RequestUploadBitmapMessage( mEventThreadServices,
436 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
438 RequestUploadBitmapMessage( mEventThreadServices,
446 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
448 DALI_ASSERT_DEBUG( ticket );
450 ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
451 if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
453 discardable = ResourcePolicy::DISCARD;
456 RequestUpdateMeshMessage( mEventThreadServices,
463 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
465 DALI_ASSERT_DEBUG( ticket );
467 Bitmap* bitmap = NULL;
468 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
470 if( iter != mImpl->mBitmaps.end() )
472 bitmap = iter->second;
477 /********************************************************************************
478 ******************** ResourceTicketLifetimeObserver methods ****************
479 ********************************************************************************/
481 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
483 const ResourceId deadId = ticket.GetId();
484 const ResourceTypePath& typePath = ticket.GetTypePath();
486 // Ensure associated event owned resources are also removed
487 mImpl->mBitmaps.erase(ticket.GetId());
489 // The ticket object is dead, remove from tickets container
490 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
491 DALI_ASSERT_DEBUG(erased != 0);
492 (void)erased; // Avoid "unused variable erased" in release builds
494 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
495 RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
498 /********************************************************************************
499 *********************** Notifications from ResourceManager ******************
500 ********************************************************************************/
502 void ResourceClient::NotifyUploaded( ResourceId id )
504 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
506 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
507 if(ticketIter != mImpl->mTickets.end())
509 ResourceTicket* ticket = ticketIter->second;
514 void ResourceClient::NotifySaveRequested( ResourceId id )
516 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
518 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
519 if(ticketIter != mImpl->mTickets.end())
521 ResourceTicket* ticket = ticketIter->second;
522 SaveResource( ticket, "" );
527 void ResourceClient::NotifyLoading( ResourceId id )
529 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
531 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
532 if(ticketIter != mImpl->mTickets.end())
534 ResourceTicket* ticket = ticketIter->second;
539 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
541 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
543 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
544 if(ticketIter != mImpl->mTickets.end())
546 ResourceTicket* ticket = ticketIter->second;
547 ticket->LoadingSucceeded();
551 void ResourceClient::NotifyLoadingFailed( ResourceId id )
553 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
555 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
556 if(ticketIter != mImpl->mTickets.end())
558 ResourceTicket* ticket = ticketIter->second;
559 ticket->LoadingFailed();
563 void ResourceClient::NotifySavingSucceeded( ResourceId id )
565 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
567 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
568 if(ticketIter != mImpl->mTickets.end())
570 ResourceTicket* ticket = ticketIter->second;
571 ticket->SavingSucceeded();
575 void ResourceClient::NotifySavingFailed( ResourceId id )
577 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
579 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
580 if(ticketIter != mImpl->mTickets.end())
582 ResourceTicket* ticket = ticketIter->second;
583 ticket->SavingFailed();
587 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
589 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
591 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
592 if(ticketIter != mImpl->mTickets.end())
594 ResourceTicket* ticket = ticketIter->second;
595 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
598 imageTicket->mAttributes = imageAttributes;