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());
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 ( NativeImageInterface& 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 newTicket->LoadingSucceeded();
330 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
332 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
334 RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
339 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
341 ImageTicketPtr newTicket;
343 const ResourceId newId = ++(mImpl->mNextId);
345 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height);
346 RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
347 ResourceTypePath typePath(renderTargetResourceType, "");
348 newTicket = new ImageTicket(*this, newId, typePath);
349 newTicket->mAttributes = imageAttributes;
350 newTicket->LoadingSucceeded();
352 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
354 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
355 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
360 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
362 ImageTicketPtr newTicket;
364 const ResourceId newId = ++(mImpl->mNextId);
366 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight() );
367 RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
368 ResourceTypePath typePath(renderTargetResourceType, "");
369 newTicket = new ImageTicket(*this, newId, typePath);
370 newTicket->mAttributes = imageAttributes;
371 newTicket->LoadingSucceeded();
373 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
375 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
376 RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
382 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
384 Pixel::Format pixelformat )
386 ImageTicketPtr newTicket;
387 const ResourceId newId = ++(mImpl->mNextId);
389 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height);
390 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
391 ResourceTypePath typePath(bitmapResourceType, "");
392 newTicket = new ImageTicket(*this, newId, typePath);
394 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
395 newTicket->mAttributes = imageAttributes;
396 newTicket->LoadingSucceeded();
398 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
400 RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
405 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
407 ResourceTicketPtr newTicket;
408 const ResourceId newId = ++(mImpl->mNextId);
409 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
410 ResourceTypePath typePath(meshResourceType, "");
411 newTicket = new ResourceTicket(*this, newId, typePath);
412 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
414 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
415 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
420 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
422 DALI_ASSERT_DEBUG( ticket );
424 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
427 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
429 RequestUploadBitmapMessage( mUpdateManager.GetEventToUpdate(),
437 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
439 DALI_ASSERT_DEBUG( ticket );
441 ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
442 if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
444 discardable = ResourcePolicy::DISCARD;
447 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
454 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
456 DALI_ASSERT_DEBUG( ticket );
458 Bitmap* bitmap = NULL;
459 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
461 if( iter != mImpl->mBitmaps.end() )
463 bitmap = iter->second;
468 /********************************************************************************
469 ******************** ResourceTicketLifetimeObserver methods ****************
470 ********************************************************************************/
472 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
474 const ResourceId deadId = ticket.GetId();
475 const ResourceTypePath& typePath = ticket.GetTypePath();
477 // Ensure associated event owned resources are also removed
478 mImpl->mBitmaps.erase(ticket.GetId());
480 // The ticket object is dead, remove from tickets container
481 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
482 DALI_ASSERT_DEBUG(erased != 0);
483 (void)erased; // Avoid "unused variable erased" in release builds
485 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
486 RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
489 /********************************************************************************
490 *********************** Notifications from ResourceManager ******************
491 ********************************************************************************/
493 void ResourceClient::NotifyUploaded( ResourceId id )
495 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
497 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
498 if(ticketIter != mImpl->mTickets.end())
500 ResourceTicket* ticket = ticketIter->second;
505 void ResourceClient::NotifySaveRequested( ResourceId id )
507 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
509 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
510 if(ticketIter != mImpl->mTickets.end())
512 ResourceTicket* ticket = ticketIter->second;
513 SaveResource( ticket, "" );
518 void ResourceClient::NotifyLoading( ResourceId id )
520 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
522 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
523 if(ticketIter != mImpl->mTickets.end())
525 ResourceTicket* ticket = ticketIter->second;
530 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
532 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
534 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
535 if(ticketIter != mImpl->mTickets.end())
537 ResourceTicket* ticket = ticketIter->second;
538 ticket->LoadingSucceeded();
542 void ResourceClient::NotifyLoadingFailed( ResourceId id )
544 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
546 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
547 if(ticketIter != mImpl->mTickets.end())
549 ResourceTicket* ticket = ticketIter->second;
550 ticket->LoadingFailed();
554 void ResourceClient::NotifySavingSucceeded( ResourceId id )
556 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
558 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
559 if(ticketIter != mImpl->mTickets.end())
561 ResourceTicket* ticket = ticketIter->second;
562 ticket->SavingSucceeded();
566 void ResourceClient::NotifySavingFailed( ResourceId id )
568 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
570 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
571 if(ticketIter != mImpl->mTickets.end())
573 ResourceTicket* ticket = ticketIter->second;
574 ticket->SavingFailed();
578 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
580 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
582 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
583 if(ticketIter != mImpl->mTickets.end())
585 ResourceTicket* ticket = ticketIter->second;
586 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
589 imageTicket->mAttributes = imageAttributes;