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