Changed image loaders to use new PixelBuffer class.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / texture-manager.h
1 #ifndef DALI_TOOLKIT_TEXTURE_MANAGER_H
2 #define DALI_TOOLKIT_TEXTURE_MANAGER_H
3
4 /*
5  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 // EXTERNAL INCLUDES
21 #include <string>
22 #include <dali/public-api/common/dali-vector.h>
23 #include <dali/public-api/object/ref-object.h>
24 #include <dali/public-api/rendering/texture-set.h>
25 #include <dali/devel-api/common/owner-container.h>
26 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
27 #include <deque>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
31 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
32 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
33 #include <dali-toolkit/internal/visuals/visual-url.h>
34
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 class MaskTextureObserver;
46
47 /**
48  * The TextureManager provides a common Image loading API for Visuals.
49  *
50  * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
51  * Texture caching is provided and performed when possible.
52  * Broken Images are automatically provided on load failure.
53  */
54 class TextureManager : public ConnectionTracker
55 {
56 public:
57
58   typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
59   static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
60
61   /**
62    * Whether the texture should be atlased or uploaded into it's own GPU texture
63    */
64   enum UseAtlas
65   {
66     NO_ATLAS,
67     USE_ATLAS
68   };
69
70   /**
71    * Whether the pixel data should be kept in TextureManager, or uploaded for rendering
72    */
73   enum StorageType
74   {
75     KEEP_PIXEL_BUFFER,
76     UPLOAD_TO_TEXTURE
77   };
78
79   /**
80    * Whether the texture should be loaded synchronously or asynchronously.
81    */
82   enum LoadType
83   {
84     LOAD_ASYNCHRONOUSLY,
85     LOAD_SYNCHRONOUSLY
86   };
87
88   /**
89    * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
90    */
91   enum LoadState
92   {
93     NOT_STARTED,     ///< Default
94     LOADING,         ///< Loading has been started, but not finished.
95     LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
96     WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
97     UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
98     CANCELLED,       ///< Removed before loading completed
99     LOAD_FAILED      ///< Async loading failed, e.g. connection problem
100   };
101
102 public:
103
104   /**
105    * Constructor.
106    */
107   TextureManager();
108
109   /**
110    * Destructor.
111    */
112   ~TextureManager();
113
114
115   // TextureManager Main API:
116
117   /**
118    * @brief Requests an image load of the given URL.
119    *
120    * The parameters are used to specify how the image is loaded.
121    * The observer has the UploadComplete method called when the load is ready.
122    *
123    * When the client has finished with the Texture, Remove() should be called.
124    *
125    * @param[in] url               The URL of the image to load
126    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
127    * @param[in] fittingMode       The FittingMode to use
128    * @param[in] samplingMode      The SamplingMode to use
129    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
130    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
131    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
132    *                              This is called when an image load completes (or fails).
133    * @return                      A TextureId to use as a handle to reference this Texture
134    */
135   TextureId RequestLoad( const VisualUrl&         url,
136                          const ImageDimensions    desiredSize,
137                          FittingMode::Type        fittingMode,
138                          Dali::SamplingMode::Type samplingMode,
139                          const UseAtlas           useAtlasing,
140                          TextureUploadObserver*   observer );
141
142   /**
143    * @brief Requests an image load of the given URL, when the texture has
144    * have loaded, it will perform a blend with the image mask, and upload
145    * the blended texture.
146    *
147    * The parameters are used to specify how the image is loaded.
148    * The observer has the UploadComplete method called when the load is ready.
149    *
150    * When the client has finished with the Texture, Remove() should be called.
151    *
152    * @param[in] url               The URL of the image to load
153    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
154    * @param[in] fittingMode       The FittingMode to use
155    * @param[in] samplingMode      The SamplingMode to use
156    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
157    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
158    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
159    *                              This is called when an image load completes (or fails).
160    * @return                      A TextureId to use as a handle to reference this Texture
161    */
162   TextureId RequestLoad( const VisualUrl&         url,
163                          TextureId                maskTextureId,
164                          const ImageDimensions    desiredSize,
165                          FittingMode::Type        fittingMode,
166                          Dali::SamplingMode::Type samplingMode,
167                          const UseAtlas           useAtlasing,
168                          TextureUploadObserver*   observer );
169
170   /**
171    * Requests a masking image to be loaded. This mask is not uploaded to GL,
172    * instead, it is stored in CPU memory, and can be used for CPU blending.
173    */
174   TextureId RequestMaskLoad( const VisualUrl& maskUrl );
175
176   /**
177    * @brief Remove a Texture from the TextureManager.
178    *
179    * Textures are cached and therefore only the removal of the last
180    * occurrence of a Texture will cause its removal internally.
181    *
182    * @param[in] textureId The ID of the Texture to remove.
183    */
184   void Remove( const TextureManager::TextureId textureId );
185
186   /**
187    * Get the visualUrl associated with the texture id
188    */
189   const VisualUrl& GetVisualUrl( TextureId textureId );
190
191   /**
192    * @brief Get the current state of a texture
193    * @param[in] textureId The texture id to query
194    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
195    * is not valid.
196    */
197   LoadState GetTextureState( TextureId textureId );
198
199   /**
200    * @brief Get the associated texture set if the texture id is valid
201    * @param[in] textureId The texture Id to look up
202    * @return the associated texture set, or an empty handle if textureId is not valid
203    */
204   TextureSet GetTextureSet( TextureId textureId );
205
206 private:
207
208   /**
209    * @brief Requests an image load of the given URL, when the texture has
210    * have loaded, if there is a valid maskTextureId, it will perform a
211    * CPU blend with the mask, and upload the blend texture.
212    *
213    * The parameters are used to specify how the image is loaded.
214    * The observer has the UploadComplete method called when the load is ready.
215    *
216    * When the client has finished with the Texture, Remove() should be called.
217    *
218    * @param[in] url               The URL of the image to load
219    * @param[in] maskTextureId     The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
220    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
221    * @param[in] fittingMode       The FittingMode to use
222    * @param[in] samplingMode      The SamplingMode to use
223    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
224    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
225    * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
226    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
227    *                              This is called when an image load completes (or fails).
228    * @return                      A TextureId to use as a handle to reference this Texture
229    */
230   TextureId RequestLoadInternal(
231     const VisualUrl&         url,
232     TextureId                maskTextureId,
233     const ImageDimensions    desiredSize,
234     FittingMode::Type        fittingMode,
235     Dali::SamplingMode::Type samplingMode,
236     UseAtlas                 useAtlas,
237     StorageType              storageType,
238     TextureUploadObserver*   observer );
239
240
241   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
242
243   /**
244    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
245    */
246   struct TextureInfo
247   {
248     TextureInfo( TextureId textureId,
249                  TextureId maskTextureId,
250                  const VisualUrl& url,
251                  ImageDimensions desiredSize,
252                  FittingMode::Type fittingMode,
253                  Dali::SamplingMode::Type samplingMode,
254                  bool loadSynchronously,
255                  UseAtlas useAtlas,
256                  TextureManager::TextureHash hash )
257     : url( url ),
258       desiredSize( desiredSize ),
259       useSize( desiredSize ),
260       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
261       textureId( textureId ),
262       maskTextureId( maskTextureId ),
263       hash( hash ),
264       referenceCount( 1u ),
265       loadState( NOT_STARTED ),
266       fittingMode( fittingMode ),
267       samplingMode( samplingMode ),
268       storageType( UPLOAD_TO_TEXTURE ),
269       loadSynchronously( loadSynchronously ),
270       useAtlas( useAtlas )
271     {
272     }
273
274     /**
275      * Container type used to store all observer clients of this Texture
276      */
277     typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
278
279     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
280     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
281     Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
282     TextureSet textureSet;         ///< The TextureSet holding the Texture
283     VisualUrl url;                 ///< The URL of the image
284     ImageDimensions desiredSize;   ///< The size requested
285     ImageDimensions useSize;       ///< The size used
286     Vector4 atlasRect;             ///< The atlas rect used if atlased
287     TextureId textureId;           ///< The TextureId associated with this Texture
288     TextureId maskTextureId;       ///< The mask TextureId to be applied on load
289     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
290     int16_t referenceCount;        ///< The reference count of clients using this Texture
291     LoadState loadState:3;         ///< The load state showing the load progress of the Texture
292     FittingMode::Type fittingMode:2; ///< The requested FittingMode
293     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
294     StorageType storageType:1;     ///< CPU storage / GPU upload;
295     bool loadSynchronously:1;      ///< True if synchronous loading was requested
296     UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
297   };
298
299   // Structs:
300
301   /**
302    * Struct to hold information about a requested Async load.
303    * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
304    */
305   struct AsyncLoadingInfo
306   {
307     AsyncLoadingInfo( TextureId textureId )
308     : textureId( textureId ),
309       loadId( 0 )
310     {
311     }
312
313     TextureId           textureId;   ///< The external Texture Id assigned to this load
314     unsigned short      loadId;      ///< The load Id used by the async loader to reference this load
315   };
316
317   /**
318    * @brief This struct is used within a container to manage atlas creation and destruction.
319    */
320   struct AtlasInfo
321   {
322     AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
323     : atlas( atlas ),
324       textureSet( textureSet )
325     {
326     }
327
328     Toolkit::ImageAtlas                 atlas;                          ///< The ImageAtlas object
329     TextureSet                          textureSet;                     ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
330   };
331
332   // Private typedefs:
333
334   typedef std::deque<AsyncLoadingInfo>  AsyncLoadingInfoContainerType;  ///< The container type used to manage Asynchronous loads in progress
335   typedef std::vector<AtlasInfo>        AtlasInfoContainerType;         ///< The container type used to manage Atlas creation and destruction
336   typedef std::vector<TextureInfo>      TextureInfoContainerType;       ///< The container type used to manage the life-cycle and caching of Textures
337
338   /**
339    * @brief Used internally to initiate a load.
340    * @param[in] textureInfo The TextureInfo struct associated with the Texture
341    * @return                True if the load was initiated
342    */
343   bool LoadTexture( TextureInfo& textureInfo );
344
345   /**
346    * Add the observer to the observer list
347    * @param[in] textureInfo The TextureInfo struct associated with the texture
348    * observer The observer wishing to observe the texture upload
349    */
350   void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
351
352   /**
353    * @brief This signal handler is called when the async local loader finishes loading.
354    * @param[in] id        This is the async image loaders Id
355    * @param[in] pixelBuffer The loaded image data
356    */
357   void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
358
359   /**
360    * @brief This signal handler is called when the async local loader finishes loading.
361    * @param[in] id        This is the async image loaders Id
362    * @param[in] pixelBuffer The loaded image data
363    */
364   void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
365
366   /**
367    * Common method to handle loading completion
368    * @param[in] container The Async loading container
369    * @param[in] id        This is the async image loaders Id
370    * @param[in] pixelBuffer The loaded image data
371    */
372   void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
373
374   /**
375    * @brief Performs Post-Load steps including atlasing.
376    * @param[in] textureInfo The struct associated with this Texture
377    * @param[in] pixelBuffer The image pixelBuffer
378    * @return    True if successful
379    */
380   void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
381
382   /**
383    * Check if there is a texture waiting to be masked. If there
384    * is then apply this mask and upload it.
385    * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
386    */
387   void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
388
389   /**
390    * Apply the mask to the pixelBuffer.
391    * @param[in] pixelBuffer The pixelBuffer to apply the mask to
392    * @param[in] maskTextureId The texture id of the mask.
393    */
394   void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId );
395
396   /**
397    * Upload the texture specified in pixelBuffer to the appropriate location
398    * @param[in] pixelBuffer The image data to upload
399    * @param[in] textureInfo The texture info containing the location to
400    * store the data to.
401    */
402   void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
403
404   /**
405    * Mark the texture as complete, and inform observers
406    * @param[in] textureInfo The struct associated with this Texture
407    */
408   void UploadComplete( TextureInfo& textureInfo );
409
410   /**
411    * Notify the current observers that the texture upload is complete,
412    * then remove the observers from the list.
413    * @param[in] textureInfo The struct associated with this Texture
414    * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
415    */
416   void NotifyObservers( TextureInfo& textureInfo, bool success );
417
418   /**
419    * @brief Generates a new, unique TextureId
420    * @return A unique TextureId
421    */
422   TextureManager::TextureId GenerateUniqueTextureId();
423
424   /**
425    * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
426    * @param[in] textureId The TextureId to look up
427    * @return              The cache index
428    */
429   int GetCacheIndexFromId( TextureId textureId );
430
431
432   /**
433    * @brief Generates a hash for caching based on the input parameters.
434    * Only applies size, fitting mode andsampling mode if the size is specified.
435    * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
436    * Always applies useAtlas.
437    * @param[in] url          The URL of the image to load
438    * @param[in] size         The image size
439    * @param[in] fittingMode  The FittingMode to use
440    * @param[in] samplingMode The SamplingMode to use
441    * @param[in] useAtlas     True if atlased
442    * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
443    * @return                 A hash of the provided data for caching.
444    */
445   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
446                             const FittingMode::Type fittingMode,
447                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
448                             TextureId maskTextureId );
449
450   /**
451    * @brief Looks up a cached texture by its hash.
452    * If found, the given parameters are used to check there is no hash-collision.
453    * @param[in] hash          The hash to look up
454    * @param[in] url           The URL of the image to load
455    * @param[in] size          The image size
456    * @param[in] fittingMode   The FittingMode to use
457    * @param[in] samplingMode  The SamplingMode to use
458    * @param[in] useAtlas      True if atlased
459    * @param[in] maskTextureId Optional texture ID to use to mask this image
460    * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
461    */
462   TextureManager::TextureId FindCachedTexture(
463     const TextureManager::TextureHash hash,
464     const std::string& url,
465     const ImageDimensions size,
466     const FittingMode::Type fittingMode,
467     const Dali::SamplingMode::Type samplingMode,
468     const bool useAtlas,
469     TextureId maskTextureId );
470
471
472 private:
473
474   /**
475    * Undefined copy constructor.
476    */
477   TextureManager( const TextureManager& );
478
479   /**
480    * Undefined assignment operator.
481    */
482   TextureManager& operator=( const TextureManager& rhs );
483
484   /**
485    * This is called by the TextureManagerUploadObserver when an observer is destroyed.
486    * We use the callback to know when to remove an observer from our notify list.
487    * @param[in] observer The observer that generated the callback
488    */
489   void ObserverDestroyed( TextureUploadObserver* observer );
490
491 private:  // Member Variables:
492
493   AsyncLoadingInfoContainerType         mAsyncLocalLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
494   AsyncLoadingInfoContainerType         mAsyncRemoteLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
495   AtlasInfoContainerType                mAtlasContainer;                ///< Used to manage Atlas creation and destruction
496   TextureInfoContainerType              mTextureInfoContainer;          ///< Used to manage the life-cycle and caching of Textures
497   Toolkit::AsyncImageLoader             mAsyncLocalLoader;              ///< The Asynchronous image loader used to provide all local async loads
498   Toolkit::AsyncImageLoader             mAsyncRemoteLoader;             ///< The Asynchronous image loader used to provide all remote async loads
499   TextureId                             mCurrentTextureId;              ///< The current value used for the unique Texture Id generation
500
501 };
502
503
504 } // name Internal
505
506 } // namespace Toolkit
507
508 } // namespace Dali
509
510 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_H