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/stage-impl.h>
26 #include <dali/internal/event/images/image-impl.h>
27 #include <dali/internal/update/resources/resource-manager.h>
28 #include <dali/internal/update/manager/update-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 SceneGraph::UpdateManager& updateManager,
61 ResourcePolicy::DataRetention dataRetentionPolicy)
62 : mResourceManager(resourceManager),
63 mUpdateManager(updateManager)
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 = bitmapResource.imageAttributes;
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 = nativeResource.imageAttributes;
118 newTicket = imageTicket;
121 case ResourceModel: // FALLTHROUGH
122 case ResourceTargetImage:
126 newTicket = new ResourceTicket(*this, newId, typePath);
131 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
133 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
135 RequestLoadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, priority );
139 ResourceTicketPtr ResourceClient::DecodeResource(
140 const ResourceType& type,
141 RequestBufferPtr buffer,
142 LoadResourcePriority priority )
144 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" );
145 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
146 ResourceTicketPtr newTicket;
147 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
149 ResourceTypePath typePath( type, "" );
150 ResourceId newId = 0;
152 // Create the correct ticket type for the resource:
157 // NOTE: pre-increment, otherwise we get 0 for first one.
158 newId = ++(mImpl->mNextId);
159 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
160 // Image tickets will cache the requested parameters, which are updated on successful loading
161 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
162 imageTicket->mAttributes = bitmapResource.imageAttributes;
163 newTicket = imageTicket;
168 case ResourceNativeImage:
170 case ResourceTargetImage:
174 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
180 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
181 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
183 RequestDecodeResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, buffer, priority );
189 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
190 const std::string& path )
192 ResourceTicketPtr newTicket;
194 const ResourceId newId = ++(mImpl->mNextId);
196 ResourceTypePath typePath(type, path);
197 newTicket = new ResourceTicket(*this, newId, typePath);
199 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
201 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
203 RequestLoadShaderMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath );
207 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
209 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
211 bool resourceExists = false;
212 TicketContainerIter ticketIter;
213 ticketIter = mImpl->mTickets.find(id);
215 if(ticketIter != mImpl->mTickets.end())
217 resourceExists = true;
218 // The ticket is already being observed
219 ResourceTicket* ticket = ticketIter->second;
220 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
221 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
222 DALI_ASSERT_DEBUG( typePathPtr );
223 RequestReloadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
227 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
229 return resourceExists;
232 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
234 DALI_ASSERT_DEBUG( ticket );
236 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
238 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
241 if( 0 != url.length() )
243 ResourceTypePath typePath( *(typePathPtr->type), url );
244 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
248 ResourceTypePath typePath( *typePathPtr );
249 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
254 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
256 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
258 ResourceTicketPtr ticket;
260 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
262 if ( mImpl->mTickets.end() != ticketIter )
264 ticket = ticketIter->second;
270 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
272 unsigned int bufferWidth,
273 unsigned int bufferHeight,
274 Pixel::Format pixelformat )
276 /* buffer is available via public-api, therefore not discardable */
277 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
278 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
279 DALI_ASSERT_DEBUG(packedBitmap);
281 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
282 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
283 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
285 ImageTicketPtr ticket = AddBitmapImage(bitmap);
287 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
288 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
292 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
294 DALI_ASSERT_DEBUG( bitmap != NULL );
296 ImageTicketPtr newTicket;
298 const ResourceId newId = ++(mImpl->mNextId);
300 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight(), bitmap->GetPixelFormat());
301 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
302 ResourceTypePath typePath(bitmapResourceType, "");
303 newTicket = new ImageTicket(*this, newId, typePath);
304 newTicket->mAttributes = imageAttributes;
305 newTicket->LoadingSucceeded();
307 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
309 // Store bitmap for immediate access.
310 mImpl->mBitmaps[newId] = bitmap;
312 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
313 RequestAddBitmapImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, bitmap );
318 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImage& resourceData )
320 ImageTicketPtr newTicket;
322 const ResourceId newId = ++(mImpl->mNextId);
323 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
324 ResourceTypePath typePath(nativeImageResourceType, "");
325 newTicket = new ImageTicket(*this, newId, typePath);
326 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
327 resourceData.GetHeight(),
328 resourceData.GetPixelFormat());
329 newTicket->LoadingSucceeded();
331 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
333 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
335 RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
340 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
342 ImageTicketPtr newTicket;
344 const ResourceId newId = ++(mImpl->mNextId);
346 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height, pixelFormat );
347 RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
348 ResourceTypePath typePath(renderTargetResourceType, "");
349 newTicket = new ImageTicket(*this, newId, typePath);
350 newTicket->mAttributes = imageAttributes;
351 newTicket->LoadingSucceeded();
353 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
355 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
356 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
361 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImage& nativeImage )
363 ImageTicketPtr newTicket;
365 const ResourceId newId = ++(mImpl->mNextId);
367 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight(), nativeImage.GetPixelFormat() );
368 RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
369 ResourceTypePath typePath(renderTargetResourceType, "");
370 newTicket = new ImageTicket(*this, newId, typePath);
371 newTicket->mAttributes = imageAttributes;
372 newTicket->LoadingSucceeded();
374 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
376 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
377 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
383 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
385 Pixel::Format pixelformat )
387 ImageTicketPtr newTicket;
388 const ResourceId newId = ++(mImpl->mNextId);
390 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height, pixelformat);
391 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
392 ResourceTypePath typePath(bitmapResourceType, "");
393 newTicket = new ImageTicket(*this, newId, typePath);
395 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
396 newTicket->mAttributes = imageAttributes;
397 newTicket->LoadingSucceeded();
399 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
401 RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
406 void ResourceClient::UpdateTexture( ResourceId id,
407 BitmapUploadArray uploadArray )
409 RequestUpdateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, uploadArray );
412 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
414 ResourceTicketPtr newTicket;
415 const ResourceId newId = ++(mImpl->mNextId);
416 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
417 ResourceTypePath typePath(meshResourceType, "");
418 newTicket = new ResourceTicket(*this, newId, typePath);
419 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
421 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
422 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
427 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
429 DALI_ASSERT_DEBUG( ticket );
431 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
434 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
436 DALI_ASSERT_DEBUG( ticket );
438 ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
439 if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
441 discardable = ResourcePolicy::DISCARD;
444 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
451 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
453 DALI_ASSERT_DEBUG( ticket );
455 Bitmap* bitmap = NULL;
456 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
458 if( iter != mImpl->mBitmaps.end() )
460 bitmap = iter->second;
465 /********************************************************************************
466 ******************** ResourceTicketLifetimeObserver methods ****************
467 ********************************************************************************/
469 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
471 const ResourceId deadId = ticket.GetId();
472 const ResourceTypePath& typePath = ticket.GetTypePath();
474 // Ensure associated event owned resources are also removed
475 mImpl->mBitmaps.erase(ticket.GetId());
477 // The ticket object is dead, remove from tickets container
478 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
479 DALI_ASSERT_DEBUG(erased != 0);
480 (void)erased; // Avoid "unused variable erased" in release builds
482 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
483 RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
486 /********************************************************************************
487 *********************** Notifications from ResourceManager ******************
488 ********************************************************************************/
490 void ResourceClient::NotifyUploaded( ResourceId id )
492 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
494 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
495 if(ticketIter != mImpl->mTickets.end())
497 ResourceTicket* ticket = ticketIter->second;
502 void ResourceClient::NotifySaveRequested( ResourceId id )
504 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
506 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
507 if(ticketIter != mImpl->mTickets.end())
509 ResourceTicket* ticket = ticketIter->second;
510 SaveResource( ticket, "" );
515 void ResourceClient::NotifyLoading( ResourceId id )
517 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(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::NotifyLoadingSucceeded( ResourceId id )
529 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
531 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
532 if(ticketIter != mImpl->mTickets.end())
534 ResourceTicket* ticket = ticketIter->second;
535 ticket->LoadingSucceeded();
539 void ResourceClient::NotifyLoadingFailed( ResourceId id )
541 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
543 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
544 if(ticketIter != mImpl->mTickets.end())
546 ResourceTicket* ticket = ticketIter->second;
547 ticket->LoadingFailed();
551 void ResourceClient::NotifySavingSucceeded( ResourceId id )
553 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
555 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
556 if(ticketIter != mImpl->mTickets.end())
558 ResourceTicket* ticket = ticketIter->second;
559 ticket->SavingSucceeded();
563 void ResourceClient::NotifySavingFailed( ResourceId id )
565 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
567 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
568 if(ticketIter != mImpl->mTickets.end())
570 ResourceTicket* ticket = ticketIter->second;
571 ticket->SavingFailed();
575 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
577 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
579 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
580 if(ticketIter != mImpl->mTickets.end())
582 ResourceTicket* ticket = ticketIter->second;
583 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
586 imageTicket->mAttributes = imageAttributes;