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 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
408 ResourceTicketPtr newTicket;
409 const ResourceId newId = ++(mImpl->mNextId);
410 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
411 ResourceTypePath typePath(meshResourceType, "");
412 newTicket = new ResourceTicket(*this, newId, typePath);
413 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
415 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
416 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
421 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
423 DALI_ASSERT_DEBUG( ticket );
425 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
428 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
430 DALI_ASSERT_DEBUG( ticket );
432 ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
433 if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
435 discardable = ResourcePolicy::DISCARD;
438 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
445 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
447 DALI_ASSERT_DEBUG( ticket );
449 Bitmap* bitmap = NULL;
450 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
452 if( iter != mImpl->mBitmaps.end() )
454 bitmap = iter->second;
459 /********************************************************************************
460 ******************** ResourceTicketLifetimeObserver methods ****************
461 ********************************************************************************/
463 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
465 const ResourceId deadId = ticket.GetId();
466 const ResourceTypePath& typePath = ticket.GetTypePath();
468 // Ensure associated event owned resources are also removed
469 mImpl->mBitmaps.erase(ticket.GetId());
471 // The ticket object is dead, remove from tickets container
472 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
473 DALI_ASSERT_DEBUG(erased != 0);
474 (void)erased; // Avoid "unused variable erased" in release builds
476 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
477 RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
480 /********************************************************************************
481 *********************** Notifications from ResourceManager ******************
482 ********************************************************************************/
484 void ResourceClient::NotifyUploaded( ResourceId id )
486 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
488 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
489 if(ticketIter != mImpl->mTickets.end())
491 ResourceTicket* ticket = ticketIter->second;
496 void ResourceClient::NotifySaveRequested( ResourceId id )
498 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
500 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
501 if(ticketIter != mImpl->mTickets.end())
503 ResourceTicket* ticket = ticketIter->second;
504 SaveResource( ticket, "" );
509 void ResourceClient::NotifyLoading( ResourceId id )
511 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
513 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
514 if(ticketIter != mImpl->mTickets.end())
516 ResourceTicket* ticket = ticketIter->second;
521 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
523 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
525 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
526 if(ticketIter != mImpl->mTickets.end())
528 ResourceTicket* ticket = ticketIter->second;
529 ticket->LoadingSucceeded();
533 void ResourceClient::NotifyLoadingFailed( ResourceId id )
535 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
537 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
538 if(ticketIter != mImpl->mTickets.end())
540 ResourceTicket* ticket = ticketIter->second;
541 ticket->LoadingFailed();
545 void ResourceClient::NotifySavingSucceeded( ResourceId id )
547 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
549 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
550 if(ticketIter != mImpl->mTickets.end())
552 ResourceTicket* ticket = ticketIter->second;
553 ticket->SavingSucceeded();
557 void ResourceClient::NotifySavingFailed( ResourceId id )
559 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
561 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
562 if(ticketIter != mImpl->mTickets.end())
564 ResourceTicket* ticket = ticketIter->second;
565 ticket->SavingFailed();
569 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
571 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
573 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
574 if(ticketIter != mImpl->mTickets.end())
576 ResourceTicket* ticket = ticketIter->second;
577 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
580 imageTicket->mAttributes = imageAttributes;