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:
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( mEventThreadServices, 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.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );;
160 newTicket = imageTicket;
165 case ResourceNativeImage:
166 case ResourceTargetImage:
168 DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
174 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
175 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
177 RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
183 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
185 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
187 bool resourceExists = false;
188 TicketContainerIter ticketIter;
189 ticketIter = mImpl->mTickets.find(id);
191 if(ticketIter != mImpl->mTickets.end())
193 resourceExists = true;
194 // The ticket is already being observed
195 ResourceTicket* ticket = ticketIter->second;
196 DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
197 const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
198 DALI_ASSERT_DEBUG( typePathPtr );
199 RequestReloadResourceMessage( mEventThreadServices, mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
203 DALI_LOG_ERROR ("Resource %d does not exist\n", id);
205 return resourceExists;
208 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
210 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
212 ResourceTicketPtr ticket;
214 TicketContainerIter ticketIter = mImpl->mTickets.find( id );
216 if ( mImpl->mTickets.end() != ticketIter )
218 ticket = ticketIter->second;
224 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
226 unsigned int bufferWidth,
227 unsigned int bufferHeight,
228 Pixel::Format pixelformat )
230 /* buffer is available via public-api, therefore not discardable */
231 Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
232 Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
233 DALI_ASSERT_DEBUG(packedBitmap);
235 packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
236 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
237 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
239 ImageTicketPtr ticket = AddBitmapImage(bitmap);
241 DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
242 DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
246 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
248 DALI_ASSERT_DEBUG( bitmap != NULL );
250 ImageTicketPtr newTicket;
252 const ResourceId newId = ++(mImpl->mNextId);
254 ImageAttributes imageAttributes = ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
255 BitmapResourceType bitmapResourceType( ImageDimensions::FromFloatVec2( imageAttributes.GetSize() ) ); // construct first as no copy ctor (needed to bind ref to object)
256 ResourceTypePath typePath(bitmapResourceType, "");
257 newTicket = new ImageTicket(*this, newId, typePath);
258 newTicket->mAttributes = imageAttributes;
259 newTicket->LoadingSucceeded();
261 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
263 // Store bitmap for immediate access.
264 mImpl->mBitmaps[newId] = bitmap;
266 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
267 RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
272 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
274 ImageTicketPtr newTicket;
276 const ResourceId newId = ++(mImpl->mNextId);
277 NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
278 ResourceTypePath typePath(nativeImageResourceType, "");
279 newTicket = new ImageTicket(*this, newId, typePath);
280 newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
281 resourceData.GetHeight());
282 newTicket->LoadingSucceeded();
284 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
286 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
288 RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
293 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
295 ImageTicketPtr newTicket;
297 const ResourceId newId = ++(mImpl->mNextId);
299 ImageAttributes imageAttributes = ImageAttributes::New(width, height);
300 RenderTargetResourceType renderTargetResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
301 ResourceTypePath typePath(renderTargetResourceType, "");
302 newTicket = new ImageTicket(*this, newId, typePath);
303 newTicket->mAttributes = imageAttributes;
304 newTicket->LoadingSucceeded();
306 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
308 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
309 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelFormat, bufferFormat );
314 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
316 ImageTicketPtr newTicket;
318 const ResourceId newId = ++(mImpl->mNextId);
320 ImageAttributes imageAttributes = ImageAttributes::New( nativeImage.GetWidth(), nativeImage.GetHeight() );
321 RenderTargetResourceType renderTargetResourceType( ImageDimensions( nativeImage.GetWidth(), nativeImage.GetHeight() ) ); // construct first as no copy ctor (needed to bind ref to object)
322 ResourceTypePath typePath(renderTargetResourceType, "");
323 newTicket = new ImageTicket(*this, newId, typePath);
324 newTicket->mAttributes = imageAttributes;
325 newTicket->LoadingSucceeded();
327 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
329 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
330 RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
336 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
338 Pixel::Format pixelformat )
340 ImageTicketPtr newTicket;
341 const ResourceId newId = ++(mImpl->mNextId);
343 ImageAttributes imageAttributes = ImageAttributes::New( width, height);
344 BitmapResourceType bitmapResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
345 ResourceTypePath typePath(bitmapResourceType, "");
346 newTicket = new ImageTicket(*this, newId, typePath);
348 mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
349 newTicket->mAttributes = imageAttributes;
350 newTicket->LoadingSucceeded();
352 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
354 RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
359 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
361 DALI_ASSERT_DEBUG( ticket );
363 RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
366 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
368 RequestUploadBitmapMessage( mEventThreadServices,
377 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
379 RequestUploadBitmapMessage( mEventThreadServices,
387 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
389 DALI_ASSERT_DEBUG( ticket );
391 Bitmap* bitmap = NULL;
392 BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
394 if( iter != mImpl->mBitmaps.end() )
396 bitmap = iter->second;
401 void ResourceClient::CreateGlTexture( ResourceId id )
403 RequestCreateGlTextureMessage( mEventThreadServices, mResourceManager, id );
407 /********************************************************************************
408 ******************** ResourceTicketLifetimeObserver methods ****************
409 ********************************************************************************/
411 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
413 const ResourceId deadId = ticket.GetId();
414 const ResourceTypePath& typePath = ticket.GetTypePath();
416 // Ensure associated event owned resources are also removed
417 mImpl->mBitmaps.erase(ticket.GetId());
419 // The ticket object is dead, remove from tickets container
420 TicketContainerSize erased = mImpl->mTickets.erase(deadId);
421 DALI_ASSERT_DEBUG(erased != 0);
422 (void)erased; // Avoid "unused variable erased" in release builds
424 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
425 RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
428 /********************************************************************************
429 *********************** Notifications from ResourceManager ******************
430 ********************************************************************************/
432 void ResourceClient::NotifyUploaded( ResourceId id )
434 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
436 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
437 if(ticketIter != mImpl->mTickets.end())
439 ResourceTicket* ticket = ticketIter->second;
444 void ResourceClient::NotifyLoading( ResourceId id )
446 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
448 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
449 if(ticketIter != mImpl->mTickets.end())
451 ResourceTicket* ticket = ticketIter->second;
456 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
458 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
460 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
461 if(ticketIter != mImpl->mTickets.end())
463 ResourceTicket* ticket = ticketIter->second;
464 ticket->LoadingSucceeded();
468 void ResourceClient::NotifyLoadingFailed( ResourceId id )
470 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
472 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
473 if(ticketIter != mImpl->mTickets.end())
475 ResourceTicket* ticket = ticketIter->second;
476 ticket->LoadingFailed();
480 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
482 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
484 TicketContainerIter ticketIter = mImpl->mTickets.find(id);
485 if(ticketIter != mImpl->mTickets.end())
487 ResourceTicket* ticket = ticketIter->second;
488 ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
491 imageTicket->mAttributes = imageAttributes;