c0f7bf01df6910cc2aa70a2dc1d0a26e3105195d
[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 struct ResourceClient::Impl
43 {
44   Impl()
45   : mNextId(0)
46   {
47   }
48
49   ResourceId       mNextId;
50   TicketContainer  mTickets;
51 };
52
53 ResourceClient::ResourceClient( ResourceManager& resourceManager,
54                                 EventThreadServices& eventThreadServices)
55 : mResourceManager(resourceManager),
56   mEventThreadServices(eventThreadServices)
57 {
58   mImpl = new ResourceClient::Impl();
59   mResourceManager.SetClient(*this);
60 }
61
62 ResourceClient::~ResourceClient()
63 {
64   // Guard to allow handle destruction after Core has been destroyed
65   if ( Stage::IsInstalled() )
66   {
67     for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
68     {
69       (*iter).second->StopLifetimeObservation();
70     }
71   }
72   delete mImpl;
73 }
74
75 ResourceTicketPtr ResourceClient::RequestResource(
76   const ResourceType& type,
77   const std::string& path,
78   LoadResourcePriority priority )
79 {
80   ResourceTicketPtr newTicket;
81   ResourceTypePath typePath(type, path);
82   ResourceId newId = 0;
83
84   // Create the ticket first
85   // NOTE: pre-increment, otherwise we get 0 for first one.
86   newId = ++(mImpl->mNextId);
87
88   switch (type.id)
89   {
90     case ResourceBitmap:
91     {
92       const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
93       // image tickets will cache the requested parameters, which are updated on successful loading
94       ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
95       imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );
96       newTicket = imageTicket;
97       break;
98     }
99
100     case ResourceNativeImage:
101     {
102       const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
103       // image tickets will cache the requested parameters, which are updated on successful loading
104       ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
105       imageTicket->mAttributes.SetSize( nativeResource.imageDimensions.GetWidth(), nativeResource.imageDimensions.GetHeight() );
106       newTicket = imageTicket;
107       break;
108     }
109     case ResourceTargetImage:
110     {
111       newTicket = new ResourceTicket(*this, newId, typePath);
112       break;
113     }
114   }
115
116   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
117
118   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
119
120   RequestLoadResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, priority );
121   return newTicket;
122 }
123
124 ResourceTicketPtr ResourceClient::DecodeResource(
125   const ResourceType& type,
126   RequestBufferPtr buffer,
127   LoadResourcePriority priority )
128 {
129   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" );
130   DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
131   ResourceTicketPtr newTicket;
132   if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
133   {
134     ResourceTypePath typePath( type, "" );
135     ResourceId newId = 0;
136
137     // Create the correct ticket type for the resource:
138     switch (type.id)
139     {
140       case ResourceBitmap:
141       {
142         // NOTE: pre-increment, otherwise we get 0 for first one.
143         newId = ++(mImpl->mNextId);
144         const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
145         // Image tickets will cache the requested parameters, which are updated on successful loading
146         ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
147         imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );
148         newTicket = imageTicket;
149         break;
150       }
151
152       // FALLTHROUGH:
153       case ResourceNativeImage:
154       case ResourceTargetImage:
155       {
156         DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
157       }
158     }
159
160     if( newTicket )
161     {
162       mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
163       DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
164
165       RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
166     }
167   }
168   return newTicket;
169 }
170
171 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
172 {
173   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
174
175   bool resourceExists = false;
176   TicketContainerIter ticketIter;
177   ticketIter = mImpl->mTickets.find(id);
178
179   if(ticketIter != mImpl->mTickets.end())
180   {
181     resourceExists = true;
182     // The ticket is already being observed
183     ResourceTicket* ticket = ticketIter->second;
184     DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
185     const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
186     DALI_ASSERT_DEBUG( typePathPtr );
187     RequestReloadResourceMessage( mEventThreadServices, mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
188   }
189   else
190   {
191     DALI_LOG_ERROR ("Resource %d does not exist\n", id);
192   }
193   return resourceExists;
194 }
195
196 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
197 {
198   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
199
200   ResourceTicketPtr ticket;
201
202   TicketContainerIter ticketIter = mImpl->mTickets.find( id );
203
204   if ( mImpl->mTickets.end() != ticketIter )
205   {
206     ticket = ticketIter->second;
207   }
208
209   return ticket;
210 }
211
212 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
213 {
214   DALI_ASSERT_DEBUG( bitmap != NULL );
215
216   ImageTicketPtr newTicket;
217
218   const ResourceId newId = ++(mImpl->mNextId);
219
220   ImageAttributes imageAttributes = ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
221   BitmapResourceType bitmapResourceType( ImageDimensions::FromFloatVec2( imageAttributes.GetSize() ) ); // construct first as no copy ctor (needed to bind ref to object)
222   ResourceTypePath typePath(bitmapResourceType, "");
223   newTicket = new ImageTicket(*this, newId, typePath);
224   newTicket->mAttributes = imageAttributes;
225   newTicket->LoadingSucceeded();
226
227   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
228
229   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
230   RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
231
232   return newTicket;
233 }
234
235 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
236 {
237   ImageTicketPtr newTicket;
238
239   const ResourceId newId = ++(mImpl->mNextId);
240   NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
241   ResourceTypePath typePath(nativeImageResourceType, "");
242   newTicket = new ImageTicket(*this, newId, typePath);
243   newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
244                                                 resourceData.GetHeight());
245   newTicket->LoadingSucceeded();
246
247   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
248
249   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
250
251   RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
252
253   return newTicket;
254 }
255
256 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
257 {
258   ImageTicketPtr newTicket;
259
260   const ResourceId newId = ++(mImpl->mNextId);
261
262   ImageAttributes imageAttributes = ImageAttributes::New(width, height);
263   RenderTargetResourceType renderTargetResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
264   ResourceTypePath typePath(renderTargetResourceType, "");
265   newTicket = new ImageTicket(*this, newId, typePath);
266   newTicket->mAttributes = imageAttributes;
267   newTicket->LoadingSucceeded();
268
269   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
270
271   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
272   RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelFormat, bufferFormat );
273
274   return newTicket;
275 }
276
277 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
278 {
279   ImageTicketPtr newTicket;
280
281   const ResourceId newId = ++(mImpl->mNextId);
282
283   ImageAttributes imageAttributes = ImageAttributes::New( nativeImage.GetWidth(), nativeImage.GetHeight() );
284   RenderTargetResourceType renderTargetResourceType( ImageDimensions( nativeImage.GetWidth(), nativeImage.GetHeight() ) ); // construct first as no copy ctor (needed to bind ref to object)
285   ResourceTypePath typePath(renderTargetResourceType, "");
286   newTicket = new ImageTicket(*this, newId, typePath);
287   newTicket->mAttributes = imageAttributes;
288   newTicket->LoadingSucceeded();
289
290   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
291
292   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
293   RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
294
295   return newTicket;
296 }
297
298
299 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
300                                                    unsigned int height,
301                                                    Pixel::Format pixelformat )
302 {
303   ImageTicketPtr newTicket;
304   const ResourceId newId = ++(mImpl->mNextId);
305
306   ImageAttributes imageAttributes = ImageAttributes::New( width, height);
307   BitmapResourceType bitmapResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
308   ResourceTypePath typePath(bitmapResourceType, "");
309   newTicket = new ImageTicket(*this, newId, typePath);
310
311   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
312   newTicket->mAttributes = imageAttributes;
313   newTicket->LoadingSucceeded();
314
315   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
316
317   RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
318
319   return newTicket;
320 }
321
322 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
323 {
324   DALI_ASSERT_DEBUG( ticket );
325
326   RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
327 }
328
329 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
330 {
331   RequestUploadBitmapMessage( mEventThreadServices,
332                               mResourceManager,
333                               destId,
334                               srcId,
335                               xOffset,
336                               yOffset );
337 }
338
339
340 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
341 {
342   RequestUploadBitmapMessage( mEventThreadServices,
343                               mResourceManager,
344                               destId,
345                               bitmap,
346                               xOffset,
347                               yOffset );
348 }
349
350 void ResourceClient::UploadBitmap( ResourceId destId, PixelDataPtr pixelData, std::size_t xOffset, std::size_t yOffset)
351 {
352   RequestUploadBitmapMessage( mEventThreadServices,
353                               mResourceManager,
354                               destId,
355                               pixelData,
356                               xOffset,
357                               yOffset );
358 }
359
360 void ResourceClient::CreateGlTexture( ResourceId id )
361 {
362   RequestCreateGlTextureMessage( mEventThreadServices, mResourceManager, id );
363 }
364
365
366 /********************************************************************************
367  ********************   ResourceTicketLifetimeObserver methods   ****************
368  ********************************************************************************/
369
370 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
371 {
372   const ResourceId deadId = ticket.GetId();
373   const ResourceTypePath& typePath = ticket.GetTypePath();
374
375   // The ticket object is dead, remove from tickets container
376   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
377   DALI_ASSERT_DEBUG(erased != 0);
378   (void)erased; // Avoid "unused variable erased" in release builds
379
380   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
381   RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
382 }
383
384 /********************************************************************************
385  ***********************   Notifications from ResourceManager  ******************
386  ********************************************************************************/
387
388 void ResourceClient::NotifyUploaded( ResourceId id )
389 {
390   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
391
392   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
393   if(ticketIter != mImpl->mTickets.end())
394   {
395     ResourceTicket* ticket = ticketIter->second;
396     ticket->Uploaded();
397   }
398 }
399
400 void ResourceClient::NotifyLoading( ResourceId id )
401 {
402   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
403
404   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
405   if(ticketIter != mImpl->mTickets.end())
406   {
407     ResourceTicket* ticket = ticketIter->second;
408     ticket->Loading();
409   }
410 }
411
412 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
413 {
414   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
415
416   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
417   if(ticketIter != mImpl->mTickets.end())
418   {
419     ResourceTicket* ticket = ticketIter->second;
420     ticket->LoadingSucceeded();
421   }
422 }
423
424 void ResourceClient::NotifyLoadingFailed( ResourceId id )
425 {
426   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
427
428   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
429   if(ticketIter != mImpl->mTickets.end())
430   {
431     ResourceTicket* ticket = ticketIter->second;
432     ticket->LoadingFailed();
433   }
434 }
435
436 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
437 {
438   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
439
440   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
441   if(ticketIter != mImpl->mTickets.end())
442   {
443     ResourceTicket* ticket = ticketIter->second;
444     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
445     if(imageTicket)
446     {
447       imageTicket->mAttributes = imageAttributes;
448     }
449   }
450 }
451
452 } // Internal
453
454 } // Dali