Removed Resource Saving
[platform/core/uifw/dali-core.git] / dali / internal / event / resources / resource-client.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // INTERNAL INCLUDES
19 #include <dali/internal/event/resources/resource-client.h>
20 #include <dali/devel-api/common/map-wrapper.h>
21
22 #include <dali/integration-api/resource-request.h>
23 #include <dali/integration-api/debug.h>
24
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>
29
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 using namespace Dali::Integration;
36
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;
41
42 typedef std::map<ResourceId, Bitmap*>                BitmapCache;
43 typedef BitmapCache::iterator                        BitmapCacheIter;
44
45 struct ResourceClient::Impl
46 {
47   Impl(ResourcePolicy::DataRetention dataRetentionPolicy)
48   : mNextId(0),
49     mDataRetentionPolicy( dataRetentionPolicy )
50   {
51   }
52
53   ResourceId       mNextId;
54   TicketContainer  mTickets;
55   BitmapCache      mBitmaps;
56   ResourcePolicy::DataRetention mDataRetentionPolicy;
57 };
58
59 ResourceClient::ResourceClient( ResourceManager& resourceManager,
60                                 EventThreadServices& eventThreadServices,
61                                 ResourcePolicy::DataRetention dataRetentionPolicy)
62 : mResourceManager(resourceManager),
63   mEventThreadServices(eventThreadServices)
64 {
65   mImpl = new ResourceClient::Impl(dataRetentionPolicy);
66   mResourceManager.SetClient(*this);
67 }
68
69 ResourceClient::~ResourceClient()
70 {
71   // Guard to allow handle destruction after Core has been destroyed
72   if ( Stage::IsInstalled() )
73   {
74     for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
75     {
76       (*iter).second->StopLifetimeObservation();
77     }
78   }
79   delete mImpl;
80 }
81
82 ResourcePolicy::DataRetention ResourceClient::GetResourceDataRetentionPolicy()
83 {
84   return mImpl->mDataRetentionPolicy;
85 }
86
87 ResourceTicketPtr ResourceClient::RequestResource(
88   const ResourceType& type,
89   const std::string& path,
90   LoadResourcePriority priority )
91 {
92   ResourceTicketPtr newTicket;
93   ResourceTypePath typePath(type, path);
94   ResourceId newId = 0;
95
96   // Create the ticket first
97   // NOTE: pre-increment, otherwise we get 0 for first one.
98   newId = ++(mImpl->mNextId);
99
100   switch (type.id)
101   {
102     case ResourceBitmap:
103     {
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;
109       break;
110     }
111
112     case ResourceNativeImage:
113     {
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;
119       break;
120     }
121     case ResourceTargetImage:
122     {
123       newTicket = new ResourceTicket(*this, newId, typePath);
124       break;
125     }
126   }
127
128   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
129
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);
131
132   RequestLoadResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, priority );
133   return newTicket;
134 }
135
136 ResourceTicketPtr ResourceClient::DecodeResource(
137   const ResourceType& type,
138   RequestBufferPtr buffer,
139   LoadResourcePriority priority )
140 {
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.
145   {
146     ResourceTypePath typePath( type, "" );
147     ResourceId newId = 0;
148
149     // Create the correct ticket type for the resource:
150     switch (type.id)
151     {
152       case ResourceBitmap:
153       {
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;
161         break;
162       }
163
164       // FALLTHROUGH:
165       case ResourceNativeImage:
166       case ResourceTargetImage:
167       {
168         DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
169       }
170     }
171
172     if( newTicket )
173     {
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);
176
177       RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
178     }
179   }
180   return newTicket;
181 }
182
183 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
184 {
185   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
186
187   bool resourceExists = false;
188   TicketContainerIter ticketIter;
189   ticketIter = mImpl->mTickets.find(id);
190
191   if(ticketIter != mImpl->mTickets.end())
192   {
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 );
200   }
201   else
202   {
203     DALI_LOG_ERROR ("Resource %d does not exist\n", id);
204   }
205   return resourceExists;
206 }
207
208 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
209 {
210   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
211
212   ResourceTicketPtr ticket;
213
214   TicketContainerIter ticketIter = mImpl->mTickets.find( id );
215
216   if ( mImpl->mTickets.end() != ticketIter )
217   {
218     ticket = ticketIter->second;
219   }
220
221   return ticket;
222 }
223
224 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
225                                                     unsigned int height,
226                                                     unsigned int bufferWidth,
227                                                     unsigned int bufferHeight,
228                                                     Pixel::Format pixelformat )
229 {
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);
234
235   packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
236   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
237   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
238
239   ImageTicketPtr ticket = AddBitmapImage(bitmap);
240
241   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
242   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
243   return ticket;
244 }
245
246 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
247 {
248   DALI_ASSERT_DEBUG( bitmap != NULL );
249
250   ImageTicketPtr newTicket;
251
252   const ResourceId newId = ++(mImpl->mNextId);
253
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();
260
261   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
262
263   // Store bitmap for immediate access.
264   mImpl->mBitmaps[newId] = bitmap;
265
266   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
267   RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
268
269   return newTicket;
270 }
271
272 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
273 {
274   ImageTicketPtr newTicket;
275
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();
283
284   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
285
286   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
287
288   RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
289
290   return newTicket;
291 }
292
293 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
294 {
295   ImageTicketPtr newTicket;
296
297   const ResourceId newId = ++(mImpl->mNextId);
298
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();
305
306   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
307
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 );
310
311   return newTicket;
312 }
313
314 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
315 {
316   ImageTicketPtr newTicket;
317
318   const ResourceId newId = ++(mImpl->mNextId);
319
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();
326
327   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
328
329   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
330   RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
331
332   return newTicket;
333 }
334
335
336 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
337                                                    unsigned int height,
338                                                    Pixel::Format pixelformat )
339 {
340   ImageTicketPtr newTicket;
341   const ResourceId newId = ++(mImpl->mNextId);
342
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);
347
348   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
349   newTicket->mAttributes = imageAttributes;
350   newTicket->LoadingSucceeded();
351
352   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
353
354   RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
355
356   return newTicket;
357 }
358
359 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
360 {
361   DALI_ASSERT_DEBUG( ticket );
362
363   RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
364 }
365
366 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
367 {
368   RequestUploadBitmapMessage( mEventThreadServices,
369                               mResourceManager,
370                               destId,
371                               srcId,
372                               xOffset,
373                               yOffset );
374 }
375
376
377 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
378 {
379   RequestUploadBitmapMessage( mEventThreadServices,
380                               mResourceManager,
381                               destId,
382                               bitmap,
383                               xOffset,
384                               yOffset );
385 }
386
387 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
388 {
389   DALI_ASSERT_DEBUG( ticket );
390
391   Bitmap* bitmap = NULL;
392   BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
393
394   if( iter != mImpl->mBitmaps.end() )
395   {
396     bitmap = iter->second;
397   }
398   return bitmap;
399 }
400
401 void ResourceClient::CreateGlTexture( ResourceId id )
402 {
403   RequestCreateGlTextureMessage( mEventThreadServices, mResourceManager, id );
404 }
405
406
407 /********************************************************************************
408  ********************   ResourceTicketLifetimeObserver methods   ****************
409  ********************************************************************************/
410
411 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
412 {
413   const ResourceId deadId = ticket.GetId();
414   const ResourceTypePath& typePath = ticket.GetTypePath();
415
416   // Ensure associated event owned resources are also removed
417   mImpl->mBitmaps.erase(ticket.GetId());
418
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
423
424   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
425   RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
426 }
427
428 /********************************************************************************
429  ***********************   Notifications from ResourceManager  ******************
430  ********************************************************************************/
431
432 void ResourceClient::NotifyUploaded( ResourceId id )
433 {
434   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
435
436   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
437   if(ticketIter != mImpl->mTickets.end())
438   {
439     ResourceTicket* ticket = ticketIter->second;
440     ticket->Uploaded();
441   }
442 }
443
444 void ResourceClient::NotifyLoading( ResourceId id )
445 {
446   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
447
448   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
449   if(ticketIter != mImpl->mTickets.end())
450   {
451     ResourceTicket* ticket = ticketIter->second;
452     ticket->Loading();
453   }
454 }
455
456 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
457 {
458   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
459
460   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
461   if(ticketIter != mImpl->mTickets.end())
462   {
463     ResourceTicket* ticket = ticketIter->second;
464     ticket->LoadingSucceeded();
465   }
466 }
467
468 void ResourceClient::NotifyLoadingFailed( ResourceId id )
469 {
470   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
471
472   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
473   if(ticketIter != mImpl->mTickets.end())
474   {
475     ResourceTicket* ticket = ticketIter->second;
476     ticket->LoadingFailed();
477   }
478 }
479
480 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
481 {
482   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
483
484   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
485   if(ticketIter != mImpl->mTickets.end())
486   {
487     ResourceTicket* ticket = ticketIter->second;
488     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
489     if(imageTicket)
490     {
491       imageTicket->mAttributes = imageAttributes;
492     }
493   }
494 }
495
496 } // Internal
497
498 } // Dali