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
51 mGlyphLoadObserver( NULL)
56 TicketContainer mTickets;
58 GlyphLoadObserver* mGlyphLoadObserver;
61 ResourceClient::ResourceClient( ResourceManager& resourceManager,
62 SceneGraph::UpdateManager& updateManager )
63 : mResourceManager(resourceManager),
64 mUpdateManager(updateManager)
66 mImpl = new ResourceClient::Impl();
67 mResourceManager.SetClient(*this);
70 ResourceClient::~ResourceClient()
72 // Guard to allow handle destruction after Core has been destroyed
73 if ( Stage::IsInstalled() )
75 for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
77 (*iter).second->StopLifetimeObservation();
83 ResourceTicketPtr ResourceClient::RequestResource(
84 const ResourceType& type,
85 const std::string& path,
86 LoadResourcePriority priority )
88 ResourceTicketPtr newTicket;
89 ResourceTypePath typePath(type, path);
92 // Create the ticket first
93 // NOTE: pre-increment, otherwise we get 0 for first one.
94 newId = ++(mImpl->mNextId);
100 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
101 // image tickets will cache the requested parameters, which are updated on successful loading
102 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
103 imageTicket->mAttributes = bitmapResource.imageAttributes;
104 newTicket = imageTicket;
108 case ResourceNativeImage:
110 const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
111 // image tickets will cache the requested parameters, which are updated on successful loading
112 ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
113 imageTicket->mAttributes = nativeResource.imageAttributes;
114 newTicket = imageTicket;
117 case ResourceModel: // FALLTHROUGH
118 case ResourceTargetImage:
123 newTicket = new ResourceTicket(*this, newId, typePath);
128 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
130 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
132 RequestLoadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, priority );
136 ResourceTicketPtr ResourceClient::DecodeResource(
137 const ResourceType& type,
138 RequestBufferPtr buffer,
139 LoadResourcePriority priority )
141 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" );
142 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
143 ResourceTicketPtr newTicket;
144 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
146 ResourceTypePath typePath( type, "" );
147 ResourceId newId = 0;
149 // Create the correct ticket type for the resource:
154 // NOTE: pre-increment, otherwise we get 0 for first one.
155 newId = ++(mImpl->mNextId);
156 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
157 // Image tickets will cache the requested parameters, which are updated on successful loading
158 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
159 imageTicket->mAttributes = bitmapResource.imageAttributes;
160 newTicket = imageTicket;
165 case ResourceNativeImage:
167 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( mUpdateManager.GetEventToUpdate(), 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( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath );
205 bool ResourceClient::ReloadResource( ResourceId id, 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( mUpdateManager.GetEventToUpdate(), mResourceManager, id, *typePathPtr, priority );
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( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
246 ResourceTypePath typePath( *typePathPtr );
247 RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), 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 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, false/*buffer is available via public-api, therefore not discardable*/ );
275 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
276 DALI_ASSERT_DEBUG(packedBitmap);
278 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
279 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
280 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
282 ImageTicketPtr ticket = AddBitmapImage(bitmap);
284 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
285 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
289 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
291 DALI_ASSERT_DEBUG( bitmap != NULL );
293 ImageTicketPtr newTicket;
295 const ResourceId newId = ++(mImpl->mNextId);
297 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight(), bitmap->GetPixelFormat());
298 BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
299 ResourceTypePath typePath(bitmapResourceType, "");
300 newTicket = new ImageTicket(*this, newId, typePath);
301 newTicket->mAttributes = imageAttributes;
302 newTicket->LoadingSucceeded();
304 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
306 // Store bitmap for immediate access.
307 mImpl->mBitmaps[newId] = bitmap;
309 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
310 RequestAddBitmapImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, bitmap );
315 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImage& resourceData )
317 ImageTicketPtr newTicket;
319 const ResourceId newId = ++(mImpl->mNextId);
320 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
321 ResourceTypePath typePath(nativeImageResourceType, "");
322 newTicket = new ImageTicket(*this, newId, typePath);
323 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
324 resourceData.GetHeight(),
325 resourceData.GetPixelFormat());
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( mUpdateManager.GetEventToUpdate(), 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 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height, pixelFormat );
344 RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // 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( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
358 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImage& nativeImage )
360 ImageTicketPtr newTicket;
362 const ResourceId newId = ++(mImpl->mNextId);
364 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight(), nativeImage.GetPixelFormat() );
365 RenderTargetResourceType renderTargetResourceType(imageAttributes); // 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( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
380 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
382 Pixel::Format pixelformat )
384 ImageTicketPtr newTicket;
385 const ResourceId newId = ++(mImpl->mNextId);
387 Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height, pixelformat);
388 BitmapResourceType bitmapResourceType(imageAttributes); // 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( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
403 void ResourceClient::UpdateTexture( ResourceId id,
404 BitmapUploadArray uploadArray )
406 RequestUpdateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, uploadArray );
409 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
411 ResourceTicketPtr newTicket;
412 const ResourceId newId = ++(mImpl->mNextId);
413 MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
414 ResourceTypePath typePath(meshResourceType, "");
415 newTicket = new ResourceTicket(*this, newId, typePath);
416 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
418 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
419 RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
424 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
426 DALI_ASSERT_DEBUG( ticket );
428 RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
431 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
433 DALI_ASSERT_DEBUG( ticket );
435 RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
441 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
443 DALI_ASSERT_DEBUG( ticket );
445 Bitmap* bitmap = NULL;
446 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
448 if( iter != mImpl->mBitmaps.end() )
450 bitmap = iter->second;
455 void ResourceClient::SetGlyphLoadObserver( GlyphLoadObserver* glyphLoadedInterface )
457 mImpl->mGlyphLoadObserver = glyphLoadedInterface;
460 void ResourceClient::UpdateAtlasStatus( ResourceId id, ResourceId atlasId, Integration::LoadStatus loadStatus )
462 RequestAtlasUpdateMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, atlasId, loadStatus );
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::NotifyGlyphSetLoaded( ResourceId id, const GlyphSet& glyphSet, LoadStatus loadStatus )
577 if( mImpl->mGlyphLoadObserver == NULL)
579 // should not happen.
580 DALI_ASSERT_DEBUG( !"GlyphLoadObserver == NULL ");
584 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyGlyphSetLoaded(hash:%u)\n", glyphSet.mFontHash);
586 mImpl->mGlyphLoadObserver->GlyphsLoaded( id, glyphSet, loadStatus );
589 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
591 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
593 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
594 if(ticketIter != mImpl->mTickets.end())
596 ResourceTicket* ticket = ticketIter->second;
597 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
600 imageTicket->mAttributes = imageAttributes;