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/devel-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:
124 newTicket = new ResourceTicket(*this, newId, typePath);
129 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
131 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
133 RequestLoadResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, priority );
137 ResourceTicketPtr ResourceClient::DecodeResource(
138 const ResourceType& type,
139 RequestBufferPtr buffer,
140 LoadResourcePriority priority )
142 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" );
143 DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
144 ResourceTicketPtr newTicket;
145 if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
147 ResourceTypePath typePath( type, "" );
148 ResourceId newId = 0;
150 // Create the correct ticket type for the resource:
155 // NOTE: pre-increment, otherwise we get 0 for first one.
156 newId = ++(mImpl->mNextId);
157 const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
158 // Image tickets will cache the requested parameters, which are updated on successful loading
159 ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
160 imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );;
161 newTicket = imageTicket;
166 case ResourceNativeImage:
167 case ResourceTargetImage:
170 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
176 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
177 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
179 RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
185 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
186 const std::string& path )
188 ResourceTicketPtr newTicket;
190 const ResourceId newId = ++(mImpl->mNextId);
192 ResourceTypePath typePath(type, path);
193 newTicket = new ResourceTicket(*this, newId, typePath);
195 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
197 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
199 RequestLoadShaderMessage( mEventThreadServices, mResourceManager, newId, typePath );
203 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
205 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
207 bool resourceExists = false;
208 TicketContainerIter ticketIter;
209 ticketIter = mImpl->mTickets.find(id);
211 if(ticketIter != mImpl->mTickets.end())
213 resourceExists = true;
214 // The ticket is already being observed
215 ResourceTicket* ticket = ticketIter->second;
216 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
217 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
218 DALI_ASSERT_DEBUG( typePathPtr );
219 RequestReloadResourceMessage( mEventThreadServices, mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
223 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
225 return resourceExists;
228 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
230 DALI_ASSERT_DEBUG( ticket );
232 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
234 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
237 if( 0 != url.length() )
239 ResourceTypePath typePath( *(typePathPtr->type), url );
240 RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
244 ResourceTypePath typePath( *typePathPtr );
245 RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
250 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
252 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
254 ResourceTicketPtr ticket;
256 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
258 if ( mImpl->mTickets.end() != ticketIter )
260 ticket = ticketIter->second;
266 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
268 unsigned int bufferWidth,
269 unsigned int bufferHeight,
270 Pixel::Format pixelformat )
272 /* buffer is available via public-api, therefore not discardable */
273 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
274 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
275 DALI_ASSERT_DEBUG(packedBitmap);
277 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
278 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
279 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
281 ImageTicketPtr ticket = AddBitmapImage(bitmap);
283 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
284 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
288 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
290 DALI_ASSERT_DEBUG( bitmap != NULL );
292 ImageTicketPtr newTicket;
294 const ResourceId newId = ++(mImpl->mNextId);
296 ImageAttributes imageAttributes = ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
297 BitmapResourceType bitmapResourceType( ImageDimensions::FromFloatVec2( imageAttributes.GetSize() ) ); // construct first as no copy ctor (needed to bind ref to object)
298 ResourceTypePath typePath(bitmapResourceType, "");
299 newTicket = new ImageTicket(*this, newId, typePath);
300 newTicket->mAttributes = imageAttributes;
301 newTicket->LoadingSucceeded();
303 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
305 // Store bitmap for immediate access.
306 mImpl->mBitmaps[newId] = bitmap;
308 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
309 RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
314 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
316 ImageTicketPtr newTicket;
318 const ResourceId newId = ++(mImpl->mNextId);
319 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
320 ResourceTypePath typePath(nativeImageResourceType, "");
321 newTicket = new ImageTicket(*this, newId, typePath);
322 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
323 resourceData.GetHeight());
324 newTicket->LoadingSucceeded();
326 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
328 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
330 RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
335 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
337 ImageTicketPtr newTicket;
339 const ResourceId newId = ++(mImpl->mNextId);
341 ImageAttributes imageAttributes = ImageAttributes::New(width, height);
342 RenderTargetResourceType renderTargetResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
343 ResourceTypePath typePath(renderTargetResourceType, "");
344 newTicket = new ImageTicket(*this, newId, typePath);
345 newTicket->mAttributes = imageAttributes;
346 newTicket->LoadingSucceeded();
348 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
350 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
351 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelFormat );
356 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
358 ImageTicketPtr newTicket;
360 const ResourceId newId = ++(mImpl->mNextId);
362 ImageAttributes imageAttributes = ImageAttributes::New( nativeImage.GetWidth(), nativeImage.GetHeight() );
363 RenderTargetResourceType renderTargetResourceType( ImageDimensions( nativeImage.GetWidth(), nativeImage.GetHeight() ) ); // construct first as no copy ctor (needed to bind ref to object)
364 ResourceTypePath typePath(renderTargetResourceType, "");
365 newTicket = new ImageTicket(*this, newId, typePath);
366 newTicket->mAttributes = imageAttributes;
367 newTicket->LoadingSucceeded();
369 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
371 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
372 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
378 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
380 Pixel::Format pixelformat )
382 ImageTicketPtr newTicket;
383 const ResourceId newId = ++(mImpl->mNextId);
385 ImageAttributes imageAttributes = ImageAttributes::New( width, height);
386 BitmapResourceType bitmapResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
387 ResourceTypePath typePath(bitmapResourceType, "");
388 newTicket = new ImageTicket(*this, newId, typePath);
390 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
391 newTicket->mAttributes = imageAttributes;
392 newTicket->LoadingSucceeded();
394 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
396 RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
401 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
403 DALI_ASSERT_DEBUG( ticket );
405 RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
408 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
410 RequestUploadBitmapMessage( mEventThreadServices,
419 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
421 RequestUploadBitmapMessage( mEventThreadServices,
429 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
431 DALI_ASSERT_DEBUG( ticket );
433 Bitmap* bitmap = NULL;
434 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
436 if( iter != mImpl->mBitmaps.end() )
438 bitmap = iter->second;
443 void ResourceClient::CreateGlTexture( ResourceId id )
445 RequestCreateGlTextureMessage( mEventThreadServices, mResourceManager, id );
449 /********************************************************************************
450 ******************** ResourceTicketLifetimeObserver methods ****************
451 ********************************************************************************/
453 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
455 const ResourceId deadId = ticket.GetId();
456 const ResourceTypePath& typePath = ticket.GetTypePath();
458 // Ensure associated event owned resources are also removed
459 mImpl->mBitmaps.erase(ticket.GetId());
461 // The ticket object is dead, remove from tickets container
462 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
463 DALI_ASSERT_DEBUG(erased != 0);
464 (void)erased; // Avoid "unused variable erased" in release builds
466 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
467 RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
470 /********************************************************************************
471 *********************** Notifications from ResourceManager ******************
472 ********************************************************************************/
474 void ResourceClient::NotifyUploaded( ResourceId id )
476 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
478 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
479 if(ticketIter != mImpl->mTickets.end())
481 ResourceTicket* ticket = ticketIter->second;
486 void ResourceClient::NotifySaveRequested( ResourceId id )
488 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
490 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
491 if(ticketIter != mImpl->mTickets.end())
493 ResourceTicket* ticket = ticketIter->second;
494 SaveResource( ticket, "" );
499 void ResourceClient::NotifyLoading( ResourceId id )
501 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
503 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
504 if(ticketIter != mImpl->mTickets.end())
506 ResourceTicket* ticket = ticketIter->second;
511 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
513 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
515 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
516 if(ticketIter != mImpl->mTickets.end())
518 ResourceTicket* ticket = ticketIter->second;
519 ticket->LoadingSucceeded();
523 void ResourceClient::NotifyLoadingFailed( ResourceId id )
525 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
527 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
528 if(ticketIter != mImpl->mTickets.end())
530 ResourceTicket* ticket = ticketIter->second;
531 ticket->LoadingFailed();
535 void ResourceClient::NotifySavingSucceeded( ResourceId id )
537 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
539 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
540 if(ticketIter != mImpl->mTickets.end())
542 ResourceTicket* ticket = ticketIter->second;
543 ticket->SavingSucceeded();
547 void ResourceClient::NotifySavingFailed( ResourceId id )
549 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
551 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
552 if(ticketIter != mImpl->mTickets.end())
554 ResourceTicket* ticket = ticketIter->second;
555 ticket->SavingFailed();
559 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
561 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
563 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
564 if(ticketIter != mImpl->mTickets.end())
566 ResourceTicket* ticket = ticketIter->second;
567 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
570 imageTicket->mAttributes = imageAttributes;