Merge "Note that some Text propeties in devel api can't be changed" into devel/master
[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] maskTextureId     The texture id of an image to mask this with (can be INVALID if no masking required)
154    * @param[in] contentScale      The scale factor to apply to the image before masking
155    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
156    * @param[in] fittingMode       The FittingMode to use
157    * @param[in] samplingMode      The SamplingMode to use
158    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
159    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
160    * @param[in] cropToMask        Only used with masking, this will crop the scaled image to the mask size. If false, then the mask will be scaled to fit the image before being applied.
161    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
162    *                              This is called when an image load completes (or fails).
163    * @return                      A TextureId to use as a handle to reference this Texture
164    */
165   TextureId RequestLoad( const VisualUrl&         url,
166                          TextureId                maskTextureId,
167                          float                    contentScale,
168                          const ImageDimensions    desiredSize,
169                          FittingMode::Type        fittingMode,
170                          Dali::SamplingMode::Type samplingMode,
171                          const UseAtlas           useAtlasing,
172                          bool                     cropToMask,
173                          TextureUploadObserver*   observer );
174
175   /**
176    * Requests a masking image to be loaded. This mask is not uploaded to GL,
177    * instead, it is stored in CPU memory, and can be used for CPU blending.
178    */
179   TextureId RequestMaskLoad( const VisualUrl& maskUrl );
180
181   /**
182    * @brief Remove a Texture from the TextureManager.
183    *
184    * Textures are cached and therefore only the removal of the last
185    * occurrence of a Texture will cause its removal internally.
186    *
187    * @param[in] textureId The ID of the Texture to remove.
188    */
189   void Remove( const TextureManager::TextureId textureId );
190
191   /**
192    * Get the visualUrl associated with the texture id
193    */
194   const VisualUrl& GetVisualUrl( TextureId textureId );
195
196   /**
197    * @brief Get the current state of a texture
198    * @param[in] textureId The texture id to query
199    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
200    * is not valid.
201    */
202   LoadState GetTextureState( TextureId textureId );
203
204   /**
205    * @brief Get the associated texture set if the texture id is valid
206    * @param[in] textureId The texture Id to look up
207    * @return the associated texture set, or an empty handle if textureId is not valid
208    */
209   TextureSet GetTextureSet( TextureId textureId );
210
211 private:
212
213   /**
214    * @brief Requests an image load of the given URL, when the texture has
215    * have loaded, if there is a valid maskTextureId, it will perform a
216    * CPU blend with the mask, and upload the blend texture.
217    *
218    * The parameters are used to specify how the image is loaded.
219    * The observer has the UploadComplete method called when the load is ready.
220    *
221    * When the client has finished with the Texture, Remove() should be called.
222    *
223    * @param[in] url               The URL of the image to load
224    * @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
225    * @param[in] contentScale      The scaling factor to apply to the content when masking
226    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
227    * @param[in] fittingMode       The FittingMode to use
228    * @param[in] samplingMode      The SamplingMode to use
229    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
230    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
231    * @param[in] cropToMask        Whether to crop the target after masking, or scale the mask to the image before masking.
232    * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
233    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
234    *                              This is called when an image load completes (or fails).
235    * @return                      A TextureId to use as a handle to reference this Texture
236    */
237   TextureId RequestLoadInternal(
238     const VisualUrl&         url,
239     TextureId                maskTextureId,
240     float                    contentScale,
241     const ImageDimensions    desiredSize,
242     FittingMode::Type        fittingMode,
243     Dali::SamplingMode::Type samplingMode,
244     UseAtlas                 useAtlas,
245     bool                     cropToMask,
246     StorageType              storageType,
247     TextureUploadObserver*   observer );
248
249
250   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
251
252   /**
253    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
254    */
255   struct TextureInfo
256   {
257     TextureInfo( TextureId textureId,
258                  TextureId maskTextureId,
259                  const VisualUrl& url,
260                  ImageDimensions desiredSize,
261                  float scaleFactor,
262                  FittingMode::Type fittingMode,
263                  Dali::SamplingMode::Type samplingMode,
264                  bool loadSynchronously,
265                  bool cropToMask,
266                  UseAtlas useAtlas,
267                  TextureManager::TextureHash hash )
268     : url( url ),
269       desiredSize( desiredSize ),
270       useSize( desiredSize ),
271       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
272       textureId( textureId ),
273       maskTextureId( maskTextureId ),
274       hash( hash ),
275       scaleFactor( scaleFactor ),
276       referenceCount( 1u ),
277       loadState( NOT_STARTED ),
278       fittingMode( fittingMode ),
279       samplingMode( samplingMode ),
280       storageType( UPLOAD_TO_TEXTURE ),
281       loadSynchronously( loadSynchronously ),
282       useAtlas( useAtlas ),
283       cropToMask( cropToMask )
284     {
285     }
286
287     /**
288      * Container type used to store all observer clients of this Texture
289      */
290     typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
291
292     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
293     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
294     Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
295     TextureSet textureSet;         ///< The TextureSet holding the Texture
296     VisualUrl url;                 ///< The URL of the image
297     ImageDimensions desiredSize;   ///< The size requested
298     ImageDimensions useSize;       ///< The size used
299     Vector4 atlasRect;             ///< The atlas rect used if atlased
300     TextureId textureId;           ///< The TextureId associated with this Texture
301     TextureId maskTextureId;       ///< The mask TextureId to be applied on load
302     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
303     float scaleFactor;             ///< The scale factor to apply to the Texture when masking
304     int16_t referenceCount;        ///< The reference count of clients using this Texture
305     LoadState loadState:3;         ///< The load state showing the load progress of the Texture
306     FittingMode::Type fittingMode:2; ///< The requested FittingMode
307     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
308     StorageType storageType:1;     ///< CPU storage / GPU upload;
309     bool loadSynchronously:1;      ///< True if synchronous loading was requested
310     UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
311     bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
312   };
313
314   // Structs:
315
316   /**
317    * Struct to hold information about a requested Async load.
318    * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
319    */
320   struct AsyncLoadingInfo
321   {
322     AsyncLoadingInfo( TextureId textureId )
323     : textureId( textureId ),
324       loadId( 0 )
325     {
326     }
327
328     TextureId           textureId;   ///< The external Texture Id assigned to this load
329     unsigned short      loadId;      ///< The load Id used by the async loader to reference this load
330   };
331
332   /**
333    * @brief This struct is used within a container to manage atlas creation and destruction.
334    */
335   struct AtlasInfo
336   {
337     AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
338     : atlas( atlas ),
339       textureSet( textureSet )
340     {
341     }
342
343     Toolkit::ImageAtlas                 atlas;                          ///< The ImageAtlas object
344     TextureSet                          textureSet;                     ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
345   };
346
347   // Private typedefs:
348
349   typedef std::deque<AsyncLoadingInfo>  AsyncLoadingInfoContainerType;  ///< The container type used to manage Asynchronous loads in progress
350   typedef std::vector<AtlasInfo>        AtlasInfoContainerType;         ///< The container type used to manage Atlas creation and destruction
351   typedef std::vector<TextureInfo>      TextureInfoContainerType;       ///< The container type used to manage the life-cycle and caching of Textures
352
353   /**
354    * @brief Used internally to initiate a load.
355    * @param[in] textureInfo The TextureInfo struct associated with the Texture
356    * @return                True if the load was initiated
357    */
358   bool LoadTexture( TextureInfo& textureInfo );
359
360   /**
361    * Add the observer to the observer list
362    * @param[in] textureInfo The TextureInfo struct associated with the texture
363    * observer The observer wishing to observe the texture upload
364    */
365   void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
366
367   /**
368    * @brief This signal handler is called when the async local loader finishes loading.
369    * @param[in] id        This is the async image loaders Id
370    * @param[in] pixelBuffer The loaded image data
371    */
372   void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
373
374   /**
375    * @brief This signal handler is called when the async local loader finishes loading.
376    * @param[in] id        This is the async image loaders Id
377    * @param[in] pixelBuffer The loaded image data
378    */
379   void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
380
381   /**
382    * Common method to handle loading completion
383    * @param[in] container The Async loading container
384    * @param[in] id        This is the async image loaders Id
385    * @param[in] pixelBuffer The loaded image data
386    */
387   void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
388
389   /**
390    * @brief Performs Post-Load steps including atlasing.
391    * @param[in] textureInfo The struct associated with this Texture
392    * @param[in] pixelBuffer The image pixelBuffer
393    * @return    True if successful
394    */
395   void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
396
397   /**
398    * Check if there is a texture waiting to be masked. If there
399    * is then apply this mask and upload it.
400    * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
401    */
402   void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
403
404   /**
405    * Apply the mask to the pixelBuffer.
406    * @param[in] pixelBuffer The pixelBuffer to apply the mask to
407    * @param[in] maskTextureId The texture id of the mask.
408    * @param[in] contentScale The factor to scale the content
409    * @param[in] cropToMask Whether to crop the content to the mask size
410    */
411   void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId,
412                   float contentScale, bool cropToMask );
413
414   /**
415    * Upload the texture specified in pixelBuffer to the appropriate location
416    * @param[in] pixelBuffer The image data to upload
417    * @param[in] textureInfo The texture info containing the location to
418    * store the data to.
419    */
420   void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
421
422   /**
423    * Mark the texture as complete, and inform observers
424    * @param[in] textureInfo The struct associated with this Texture
425    */
426   void UploadComplete( TextureInfo& textureInfo );
427
428   /**
429    * Notify the current observers that the texture upload is complete,
430    * then remove the observers from the list.
431    * @param[in] textureInfo The struct associated with this Texture
432    * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
433    */
434   void NotifyObservers( TextureInfo& textureInfo, bool success );
435
436   /**
437    * @brief Generates a new, unique TextureId
438    * @return A unique TextureId
439    */
440   TextureManager::TextureId GenerateUniqueTextureId();
441
442   /**
443    * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
444    * @param[in] textureId The TextureId to look up
445    * @return              The cache index
446    */
447   int GetCacheIndexFromId( TextureId textureId );
448
449
450   /**
451    * @brief Generates a hash for caching based on the input parameters.
452    * Only applies size, fitting mode andsampling mode if the size is specified.
453    * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
454    * Always applies useAtlas.
455    * @param[in] url          The URL of the image to load
456    * @param[in] size         The image size
457    * @param[in] fittingMode  The FittingMode to use
458    * @param[in] samplingMode The SamplingMode to use
459    * @param[in] useAtlas     True if atlased
460    * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
461    * @return                 A hash of the provided data for caching.
462    */
463   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
464                             const FittingMode::Type fittingMode,
465                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
466                             TextureId maskTextureId );
467   /**
468    * @brief Looks up a cached texture by its hash.
469    * If found, the given parameters are used to check there is no hash-collision.
470    * @param[in] hash          The hash to look up
471    * @param[in] url           The URL of the image to load
472    * @param[in] size          The image size
473    * @param[in] fittingMode   The FittingMode to use
474    * @param[in] samplingMode  The SamplingMode to use
475    * @param[in] useAtlas      True if atlased
476    * @param[in] maskTextureId Optional texture ID to use to mask this image
477    * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
478    */
479   TextureManager::TextureId FindCachedTexture(
480     const TextureManager::TextureHash hash,
481     const std::string& url,
482     const ImageDimensions size,
483     const FittingMode::Type fittingMode,
484     const Dali::SamplingMode::Type samplingMode,
485     const bool useAtlas,
486     TextureId maskTextureId );
487
488
489 private:
490
491   /**
492    * Undefined copy constructor.
493    */
494   TextureManager( const TextureManager& );
495
496   /**
497    * Undefined assignment operator.
498    */
499   TextureManager& operator=( const TextureManager& rhs );
500
501   /**
502    * This is called by the TextureManagerUploadObserver when an observer is destroyed.
503    * We use the callback to know when to remove an observer from our notify list.
504    * @param[in] observer The observer that generated the callback
505    */
506   void ObserverDestroyed( TextureUploadObserver* observer );
507
508 private:  // Member Variables:
509
510   AsyncLoadingInfoContainerType         mAsyncLocalLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
511   AsyncLoadingInfoContainerType         mAsyncRemoteLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
512   AtlasInfoContainerType                mAtlasContainer;                ///< Used to manage Atlas creation and destruction
513   TextureInfoContainerType              mTextureInfoContainer;          ///< Used to manage the life-cycle and caching of Textures
514   Toolkit::AsyncImageLoader             mAsyncLocalLoader;              ///< The Asynchronous image loader used to provide all local async loads
515   Toolkit::AsyncImageLoader             mAsyncRemoteLoader;             ///< The Asynchronous image loader used to provide all remote async loads
516   TextureId                             mCurrentTextureId;              ///< The current value used for the unique Texture Id generation
517
518 };
519
520
521 } // name Internal
522
523 } // namespace Toolkit
524
525 } // namespace Dali
526
527 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_H