Make do not caching pixelBuffer in texture-manager.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / texture-manager-impl.h
1 #ifndef DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
2 #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
3
4 /*
5  * Copyright (c) 2020 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 <deque>
22 #include <functional>
23 #include <string>
24 #include <memory>
25 #include <dali/public-api/common/dali-vector.h>
26 #include <dali/public-api/object/ref-object.h>
27 #include <dali/public-api/rendering/texture-set.h>
28 #include <dali/devel-api/common/owner-container.h>
29 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
30 #include <dali/public-api/rendering/geometry.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
34 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
35 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
36 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
37 #include <dali-toolkit/internal/visuals/visual-url.h>
38 #include <dali-toolkit/internal/helpers/round-robin-container-view.h>
39 #include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
40
41
42 namespace Dali
43 {
44
45 namespace Toolkit
46 {
47
48 namespace Internal
49 {
50 class ImageAtlasManager;
51 typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
52
53 /**
54  * The TextureManager provides a common Image loading API for Visuals.
55  *
56  * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
57  * Texture caching is provided and performed when possible.
58  * Broken Images are automatically provided on load failure.
59  */
60 class TextureManager : public ConnectionTracker
61 {
62 public:
63
64   typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
65   static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
66
67   /**
68    * Whether the texture should be atlased or uploaded into it's own GPU texture
69    */
70   enum UseAtlas
71   {
72     NO_ATLAS,
73     USE_ATLAS
74   };
75
76   /**
77    * Whether the pixel data should be kept in TextureManager, returned with pixelBuffer or uploaded for rendering
78    */
79   enum class StorageType: uint8_t
80   {
81     KEEP_PIXEL_BUFFER,
82     RETURN_PIXEL_BUFFER,
83     UPLOAD_TO_TEXTURE
84   };
85
86   /**
87    * Whether the texture should be loaded synchronously or asynchronously.
88    */
89   enum class LoadType: uint8_t
90   {
91     LOAD_ASYNCHRONOUSLY,
92     LOAD_SYNCHRONOUSLY
93   };
94
95   /**
96    * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
97    */
98   enum class LoadState: uint8_t
99   {
100     NOT_STARTED,     ///< Default
101     LOADING,         ///< Loading has been started, but not finished.
102     LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
103     WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
104     MASK_APPLYING,   ///< Loading has finished, Mask is applying
105     MASK_APPLIED,    ///< Loading has finished, Mask is applyied by GPU
106     UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
107     CANCELLED,       ///< Removed before loading completed
108     LOAD_FAILED      ///< Async loading failed, e.g. connection problem
109   };
110
111   /**
112    * @brief Types of reloading policies
113    */
114   enum class ReloadPolicy
115   {
116     CACHED = 0,             ///< Loads cached texture if it exists.
117     FORCED                  ///< Forces reloading of texture.
118   };
119
120   /**
121    * @brief Whether to multiply alpha into color channels on load
122    */
123   enum class MultiplyOnLoad
124   {
125     LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image
126     MULTIPLY_ON_LOAD           ///< Multiply alpha into color channels on load
127   };
128
129 public:
130
131   struct MaskingData
132   {
133     MaskingData();
134     ~MaskingData() = default;
135
136     VisualUrl mAlphaMaskUrl;
137     TextureManager::TextureId mAlphaMaskId;
138     float mContentScaleFactor;
139     bool mCropToMask;
140   };
141   using MaskingDataPointer = std::unique_ptr<MaskingData>;
142
143
144   /**
145    * Class to provide lifecycle event on destruction of texture manager.
146    */
147   struct LifecycleObserver
148   {
149     /**
150      * Called shortly before the texture manager is destroyed.
151      */
152     virtual void TextureManagerDestroyed() = 0;
153   };
154
155   /**
156    * Constructor.
157    */
158   TextureManager();
159
160   /**
161    * Destructor.
162    */
163   ~TextureManager() override;
164
165   // TextureManager Main API:
166
167   /**
168    * @brief Requests an frame of animated image load.
169    *
170    * The parameters are used to specify how the animated image is loaded.
171    * The observer has the LoadComplete method called when the load is ready.
172    *
173    * @param[in] animatedImageLoading  The AnimatedImageLoading that contain the animated image information
174    * @param[in] frameIndex            The frame index to load.
175    * @param[in] samplingMode          The SamplingMode to use
176    * @param[in] synchronousLoading    true if the frame should be loaded synchronously
177    * @param[out] textureId            The textureId of the frame
178    * @param[in] wrapModeU             Horizontal Wrap mode
179    * @param[in] wrapModeV             Vertical Wrap mode
180    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
181    *                                  This is called when an image load completes (or fails).
182    *
183    * @return                          The texture set containing the frame of animated image, or empty if still loading.
184    */
185
186   TextureSet LoadAnimatedImageTexture( Dali::AnimatedImageLoading animatedImageLoading,
187                                        uint32_t frameIndex,
188                                        Dali::SamplingMode::Type samplingMode,
189                                        bool synchronousLoading,
190                                        TextureManager::TextureId& textureId,
191                                        Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV,
192                                        TextureUploadObserver* textureObserver );
193
194   /**
195    * @brief Requests an image load of the given URL to get PixelBuffer.
196    *
197    * The parameters are used to specify how the image is loaded.
198    * The observer has the LoadComplete method called when the load is ready.
199    *
200    * @param[in] url                   The URL of the image to load
201    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
202    * @param[in] fittingMode           The FittingMode to use
203    * @param[in] samplingMode          The SamplingMode to use
204    * @param[in] synchronousLoading    true if the URL should be loaded synchronously
205    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
206    *                                  This is called when an image load completes (or fails).
207    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
208    * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
209    *                                  image has no alpha channel
210    *
211    * @return                          The pixel buffer containing the image, or empty if still loading.
212    */
213
214   Devel::PixelBuffer LoadPixelBuffer( const VisualUrl& url,
215                                       Dali::ImageDimensions desiredSize,
216                                       Dali::FittingMode::Type fittingMode,
217                                       Dali::SamplingMode::Type samplingMode,
218                                       bool synchronousLoading,
219                                       TextureUploadObserver* textureObserver,
220                                       bool orientationCorrection,
221                                       TextureManager::MultiplyOnLoad& preMultiplyOnLoad );
222
223
224   /**
225    * @brief Requests an image load of the given URL.
226    *
227    * The parameters are used to specify how the image is loaded.
228    * The observer has the UploadComplete method called when the load is ready.
229    *
230    * When the client has finished with the Texture, Remove() should be called.
231    *
232    * @param[in] url                   The URL of the image to load
233    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
234    * @param[in] fittingMode           The FittingMode to use
235    * @param[in] samplingMode          The SamplingMode to use
236    * @param[in, out] maskInfo         Mask info structure
237    * @param[in] synchronousLoading    true if the URL should be loaded synchronously
238    * @param[out] textureId,           The textureId of the URL
239    * @param[out] textureRect          The rectangle within the texture atlas that this URL occupies,
240    *                                  this is the rectangle in normalized coordinates.
241    * @param[out] textureRectSize      The rectangle within the texture atlas that this URL occupies,
242    *                                  this is the same rectangle in pixels.
243    * @param[in,out] atlasingStatus    Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
244    *                                  be loaded, and marked successful, but this will be set to false.
245    *                                  If atlasing succeeds, this will be set to true.
246    * @param[out] loadingStatus        The loading status of the texture
247    * @param[in] wrapModeU             Horizontal Wrap mode
248    * @param[in] wrapModeV             Vertical Wrap mode
249    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
250    *                                  This is called when an image load completes (or fails).
251    * @param[in] atlasObserver         This is used if the texture is atlased, and will be called instead of
252    *                                  textureObserver.UploadCompleted
253    * @param[in] imageAtlasManager     The atlas manager to use for atlasing textures
254    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
255    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
256    * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
257    *                                  image has no alpha channel
258    *
259    * @return                          The texture set containing the image, or empty if still loading.
260    */
261
262   TextureSet LoadTexture( const VisualUrl&             url,
263                           Dali::ImageDimensions        desiredSize,
264                           Dali::FittingMode::Type      fittingMode,
265                           Dali::SamplingMode::Type     samplingMode,
266                           MaskingDataPointer&          maskInfo,
267                           bool                         synchronousLoading,
268                           TextureManager::TextureId&   textureId,
269                           Vector4&                     textureRect,
270                           Dali::ImageDimensions&       textureRectSize,
271                           bool&                        atlasingStatus,
272                           bool&                        loadingStatus,
273                           Dali::WrapMode::Type         wrapModeU,
274                           Dali::WrapMode::Type         wrapModeV,
275                           TextureUploadObserver*       textureObserver,
276                           AtlasUploadObserver*         atlasObserver,
277                           ImageAtlasManagerPtr         imageAtlasManager,
278                           bool                         orientationCorrection,
279                           TextureManager::ReloadPolicy reloadPolicy,
280                           MultiplyOnLoad&              preMultiplyOnLoad );
281
282   /**
283    * @brief Requests an image load of the given URL.
284    *
285    * The parameters are used to specify how the image is loaded.
286    * The observer has the UploadComplete method called when the load is ready.
287    *
288    * When the client has finished with the Texture, Remove() should be called.
289    *
290    * @param[in] url                   The URL of the image to load
291    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
292    * @param[in] fittingMode           The FittingMode to use
293    * @param[in] samplingMode          The SamplingMode to use
294    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
295    *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
296    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
297    *                                  This is called when an image load completes (or fails).
298    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
299    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
300    * @param[in,out] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
301    * @return                          A TextureId to use as a handle to reference this Texture
302    */
303   TextureId RequestLoad( const VisualUrl&                   url,
304                          const ImageDimensions              desiredSize,
305                          FittingMode::Type                  fittingMode,
306                          Dali::SamplingMode::Type           samplingMode,
307                          const UseAtlas                     useAtlasing,
308                          TextureUploadObserver*             observer,
309                          bool                               orientationCorrection,
310                          TextureManager::ReloadPolicy       reloadPolicy,
311                          MultiplyOnLoad&                    preMultiplyOnLoad );
312
313   /**
314    * @brief Requests an image load of the given URL, when the texture has
315    * have loaded, it will perform a blend with the image mask, and upload
316    * the blended texture.
317    *
318    * The parameters are used to specify how the image is loaded.
319    * The observer has the UploadComplete method called when the load is ready.
320    *
321    * When the client has finished with the Texture, Remove() should be called.
322    *
323    * @param[in] url                   The URL of the image to load
324    * @param[in] maskTextureId         The texture id of an image to mask this with
325    *                                  (can be INVALID if no masking required)
326    * @param[in] contentScale          The scale factor to apply to the image before masking
327    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
328    * @param[in] fittingMode           The FittingMode to use
329    * @param[in] samplingMode          The SamplingMode to use
330    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
331    *                                  be loaded, and marked successful,
332    *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from
333    *                                  the TextureManagerUploadObserver.
334    * @param[in] cropToMask            Only used with masking, this will crop the scaled image to the mask size.
335    *                                  If false, then the mask will be scaled to fit the image before being applied.
336    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
337    *                                  virtual.
338    *                                  This is called when an image load completes (or fails).
339    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
340    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
341    * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the
342    *                                  image has no alpha channel
343    * @return                          A TextureId to use as a handle to reference this Texture
344    */
345   TextureId RequestLoad( const VisualUrl&                   url,
346                          TextureId                          maskTextureId,
347                          float                              contentScale,
348                          const ImageDimensions              desiredSize,
349                          FittingMode::Type                  fittingMode,
350                          Dali::SamplingMode::Type           samplingMode,
351                          const UseAtlas                     useAtlasing,
352                          bool                               cropToMask,
353                          TextureUploadObserver*             observer,
354                          bool                               orientationCorrection,
355                          TextureManager::ReloadPolicy       reloadPolicy,
356                          MultiplyOnLoad&                    preMultiplyOnLoad );
357
358   /**
359    * Requests a masking image to be loaded. This mask is not uploaded to GL,
360    * instead, it is stored in CPU memory, and can be used for CPU blending.
361    */
362   TextureId RequestMaskLoad( const VisualUrl& maskUrl );
363
364   /**
365    * @brief Remove a Texture from the TextureManager.
366    *
367    * Textures are cached and therefore only the removal of the last
368    * occurrence of a Texture will cause its removal internally.
369    *
370    * @param[in] textureId The ID of the Texture to remove.
371    * @param[in] textureObserver The texture observer.
372    */
373   void Remove( const TextureManager::TextureId textureId, TextureUploadObserver* textureObserver );
374
375   /**
376    * @brief Get the visualUrl associated with the texture id.
377    * @param[in] textureId The texture Id to get
378    * @return The visual Url associated with the texture id.
379    */
380   VisualUrl GetVisualUrl( TextureId textureId );
381
382   /**
383    * @brief Get the current state of a texture
384    * @param[in] textureId The texture id to query
385    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
386    * is not valid.
387    */
388   LoadState GetTextureState( TextureId textureId );
389
390   /**
391    * @brief Get the associated texture set if the texture id is valid
392    * @param[in] textureId The texture Id to look up
393    * @return the associated texture set, or an empty handle if textureId is not valid
394    */
395   TextureSet GetTextureSet( TextureId textureId );
396
397   /**
398    * Adds an external texture to the texture manager
399    * @param[in] texture The texture to add
400    * @return string containing the URL for the texture
401    */
402   std::string AddExternalTexture( TextureSet& texture );
403
404   /**
405    * Removes an external texture from texture manager
406    * @param[in] url The string containing the texture to remove
407    * @return handle to the texture
408    */
409   TextureSet RemoveExternalTexture( const std::string& url );
410
411   /**
412    * Add an observer to the object.
413    * @param[in] observer The observer to add.
414    */
415   void AddObserver( TextureManager::LifecycleObserver& observer );
416
417   /**
418    * Remove an observer from the object
419    * @pre The observer has already been added.
420    * @param[in] observer The observer to remove.
421    */
422   void RemoveObserver( TextureManager::LifecycleObserver& observer );
423
424   /**
425    * @brief Set an image to be used when a visual has failed to correctly render
426    * @param[in] brokenImageUrl The broken image url.
427    */
428   void SetBrokenImageUrl(const std::string& brokenImageUrl);
429
430   /**
431    * @brief Get an image to be used when a visual has failed to correctly render
432    * @return Returns The broken image url.
433    */
434   const std::string GetBrokenImageUrl();
435
436   /**
437    * @brief Returns the geometry associated with texture.
438    * @param[in] textureId Id of the texture
439    * @param[out] frontElements number of front elements
440    * @param[out] backElements number of back elements
441    * @return Returns valid geometry object
442    */
443   Geometry GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements );
444
445 private:
446
447   /**
448    * @brief Requests an image load of the given URL, when the texture has
449    * have loaded, if there is a valid maskTextureId, it will perform a
450    * CPU blend with the mask, and upload the blend texture.
451    *
452    * The parameters are used to specify how the image is loaded.
453    * The observer has the UploadComplete method called when the load is ready.
454    *
455    * When the client has finished with the Texture, Remove() should be called.
456    *
457    * @param[in] url                   The URL of the image to load
458    * @param[in] maskTextureId         The texture id of an image to use as a mask. If no mask is required, then set
459    *                                  to INVALID_TEXTURE_ID
460    * @param[in] contentScale          The scaling factor to apply to the content when masking
461    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
462    * @param[in] fittingMode           The FittingMode to use
463    * @param[in] samplingMode          The SamplingMode to use
464    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be
465    *                                  loaded, and marked successful, but "useAtlasing" will be set to false in the
466    *                                  "UploadCompleted" callback from the TextureManagerUploadObserver.
467    * @param[in] cropToMask            Whether to crop the target after masking, or scale the mask to the image before
468    *                                  masking.
469    * @param[in] storageType,          Whether the pixel data is stored in the cache or uploaded to the GPU
470    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
471    *                                  virtual.
472    *                                  This is called when an image load completes (or fails).
473    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
474    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
475    * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if
476    *                                  there is no alpha
477    * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
478    * @param[in] frameIndex            The frame index of a frame to be loaded frame
479    * @return                          A TextureId to use as a handle to reference this Texture
480    */
481   TextureId RequestLoadInternal(
482     const VisualUrl&                    url,
483     TextureId                           maskTextureId,
484     float                               contentScale,
485     const ImageDimensions               desiredSize,
486     FittingMode::Type                   fittingMode,
487     Dali::SamplingMode::Type            samplingMode,
488     UseAtlas                            useAtlas,
489     bool                                cropToMask,
490     StorageType                         storageType,
491     TextureUploadObserver*              observer,
492     bool                                orientationCorrection,
493     TextureManager::ReloadPolicy        reloadPolicy,
494     MultiplyOnLoad&                     preMultiplyOnLoad,
495     Dali::AnimatedImageLoading          animatedImageLoading,
496     uint32_t                            frameIndex );
497
498   /**
499    * @brief Get the current state of a texture
500    * @param[in] textureId The texture id to query
501    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
502    * is not valid.
503    */
504   LoadState GetTextureStateInternal( TextureId textureId );
505
506   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
507
508   // Structs:
509
510   /**
511    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
512    */
513   struct TextureInfo
514   {
515     TextureInfo( TextureId textureId,
516                  TextureId maskTextureId,
517                  const VisualUrl& url,
518                  ImageDimensions desiredSize,
519                  float scaleFactor,
520                  FittingMode::Type fittingMode,
521                  Dali::SamplingMode::Type samplingMode,
522                  bool loadSynchronously,
523                  bool cropToMask,
524                  UseAtlas useAtlas,
525                  TextureManager::TextureHash hash,
526                  bool orientationCorrection,
527                  bool preMultiplyOnLoad,
528                  Dali::AnimatedImageLoading animatedImageLoading,
529                  uint32_t frameIndex )
530     : url( url ),
531       desiredSize( desiredSize ),
532       useSize( desiredSize ),
533       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
534       textureId( textureId ),
535       maskTextureId( maskTextureId ),
536       hash( hash ),
537       scaleFactor( scaleFactor ),
538       referenceCount( 1u ),
539       loadState( LoadState::NOT_STARTED ),
540       fittingMode( fittingMode ),
541       samplingMode( samplingMode ),
542       storageType( StorageType::UPLOAD_TO_TEXTURE ),
543       animatedImageLoading( animatedImageLoading ),
544       frameIndex( frameIndex ),
545       loadSynchronously( loadSynchronously ),
546       useAtlas( useAtlas ),
547       cropToMask( cropToMask ),
548       orientationCorrection( true ),
549       preMultiplyOnLoad( preMultiplyOnLoad ),
550       preMultiplied( false )
551     {
552     }
553
554     /**
555      * Container type used to store all observer clients of this Texture
556      */
557     typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
558
559     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
560     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
561     Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
562     TextureSet textureSet;         ///< The TextureSet holding the Texture
563     VisualUrl url;                 ///< The URL of the image
564     ImageDimensions desiredSize;   ///< The size requested
565     ImageDimensions useSize;       ///< The size used
566     Vector4 atlasRect;             ///< The atlas rect used if atlased
567     TextureId textureId;           ///< The TextureId associated with this Texture
568     TextureId maskTextureId;       ///< The mask TextureId to be applied on load
569     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
570     float scaleFactor;             ///< The scale factor to apply to the Texture when masking
571     int16_t referenceCount;        ///< The reference count of clients using this Texture
572     LoadState loadState;           ///< The load state showing the load progress of the Texture
573     FittingMode::Type fittingMode:3; ///< The requested FittingMode
574     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
575     StorageType storageType;       ///< CPU storage / GPU upload;
576     Dali::AnimatedImageLoading animatedImageLoading; ///< AnimatedImageLoading that contains animated image information.
577     uint32_t frameIndex;           ///< frame index that be loaded, in case of animated image
578     bool loadSynchronously:1;      ///< True if synchronous loading was requested
579     UseAtlas useAtlas:2;           ///< USE_ATLAS if an atlas was requested.
580                                    ///< This is updated to false if atlas is not used
581     bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
582     bool orientationCorrection:1;  ///< true if the image should be rotated to match exif orientation data
583     bool preMultiplyOnLoad:1;      ///< true if the image's color should be multiplied by it's alpha
584     bool preMultiplied:1;          ///< true if the image's color was multiplied by it's alpha
585   };
586
587   /**
588    * Structure to hold info about a texture load queued during NotifyObservers
589    */
590   struct LoadQueueElement
591   {
592     LoadQueueElement( TextureId textureId, TextureUploadObserver* observer )
593     : mTextureId( textureId ),
594       mObserver( observer )
595     {
596     }
597
598     TextureId mTextureId; ///< The texture id of the requested load.
599     TextureUploadObserver* mObserver; ///< Observer of texture load.
600   };
601
602   /**
603    * Struct to hold information about a requested Async load.
604    * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
605    */
606   struct AsyncLoadingInfo
607   {
608     AsyncLoadingInfo( TextureId textureId )
609     : textureId( textureId ),
610       loadId( 0 )
611     {
612     }
613
614     TextureId           textureId;   ///< The external Texture Id assigned to this load
615     uint32_t            loadId;      ///< The load Id used by the async loader to reference this load
616   };
617
618   // Private typedefs:
619
620   typedef std::deque<AsyncLoadingInfo>  AsyncLoadingInfoContainerType;  ///< The container type used to manage Asynchronous loads in progress
621   typedef std::vector<TextureInfo>      TextureInfoContainerType;       ///< The container type used to manage the life-cycle and caching of Textures
622
623   /**
624    * @brief Initiate a load or queue load if NotifyObservers is invoking callbacks
625    * @param[in] textureInfo The TextureInfo struct associated with the Texture
626    * @param[in] observer The observer wishing to observe the texture upload
627    */
628   void LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
629
630   /**
631    * @brief Queue a texture load to be subsequently handled by ProcessQueuedTextures.
632    * @param[in] textureInfo The TextureInfo struct associated with the Texture
633    * @param[in] observer The observer wishing to observe the texture upload
634    */
635   void QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
636
637   /**
638    * @brief Used internally to initiate a load.
639    * @param[in] textureInfo The TextureInfo struct associated with the Texture
640    * @param[in] observer The observer wishing to observe the texture upload
641    */
642   void LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
643
644   /**
645    * @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
646    */
647   void ProcessQueuedTextures();
648
649   /**
650    * Add the observer to the observer list
651    * @param[in] textureInfo The TextureInfo struct associated with the texture
652    * @param[in] observer The observer wishing to observe the texture upload
653    */
654   void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
655
656   /**
657    * @brief This signal handler is called when the async local loader finishes loading.
658    * @param[in] id        This is the async image loaders Id
659    * @param[in] pixelBuffer The loaded image data
660    */
661   void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
662
663   /**
664    * @brief This signal handler is called when the async local loader finishes loading.
665    * @param[in] id        This is the async image loaders Id
666    * @param[in] pixelBuffer The loaded image data
667    */
668   void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
669
670   /**
671    * Common method to handle loading completion
672    * @param[in] container The Async loading container
673    * @param[in] id        This is the async image loaders Id
674    * @param[in] pixelBuffer The loaded image data
675    */
676   void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
677
678   /**
679    * @brief Performs Post-Load steps including atlasing.
680    * @param[in] textureInfo The struct associated with this Texture
681    * @param[in] pixelBuffer The image pixelBuffer
682    * @return    True if successful
683    */
684   void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
685
686   /**
687    * Check if there is a texture waiting to be masked. If there
688    * is then apply this mask and upload it.
689    * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
690    */
691   void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
692
693   /**
694    * Apply the mask to the pixelBuffer.
695    * @param[in] textureInfo The information of texture to apply the mask to
696    * @param[in] maskTextureId The texture id of the mask.
697    */
698   void ApplyMask( TextureInfo& textureInfo, TextureId maskTextureId );
699
700   /**
701    * Upload the texture specified in pixelBuffer to the appropriate location
702    * @param[in] pixelBuffer The image data to upload
703    * @param[in] textureInfo The texture info containing the location to
704    * store the data to.
705    */
706   void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
707
708   /**
709    * Creates tiled geometry of for the texture which separates fully-opaque
710    * tiles from ones which use transparency.
711    * @param pixelBuffer
712    * @param textureInfo
713    */
714   bool CreateTiledGeometry( const Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
715
716   /**
717    * Mark the texture as complete, and inform observers
718    * @param[in] textureInfo The struct associated with this Texture
719    */
720   void UploadComplete( TextureInfo& textureInfo );
721
722   /**
723    * Notify the current observers that the texture upload is complete,
724    * then remove the observers from the list.
725    * @param[in] textureInfo The struct associated with this Texture
726    * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
727    */
728   void NotifyObservers( TextureInfo& textureInfo, bool success );
729
730   /**
731    * @brief Generates a new, unique TextureId
732    * @return A unique TextureId
733    */
734   TextureManager::TextureId GenerateUniqueTextureId();
735
736   /**
737    * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
738    * @param[in] textureId The TextureId to look up
739    * @return              The cache index
740    */
741   int GetCacheIndexFromId( TextureId textureId );
742
743
744   /**
745    * @brief Generates a hash for caching based on the input parameters.
746    * Only applies size, fitting mode andsampling mode if the size is specified.
747    * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
748    * Always applies useAtlas.
749    * @param[in] url              The URL of the image to load
750    * @param[in] size             The image size
751    * @param[in] fittingMode      The FittingMode to use
752    * @param[in] samplingMode     The SamplingMode to use
753    * @param[in] useAtlas         True if atlased
754    * @param[in] maskTextureId    The masking texture id (or INVALID_TEXTURE_ID)
755    * @param[in] isAnimatedImage  The boolean value to know whether the request is for animated image or not
756    * @param[in] frameIndex       The frame index of a frame to be loaded frame
757    * @return                     A hash of the provided data for caching.
758    */
759   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
760                             const FittingMode::Type fittingMode,
761                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
762                             TextureId maskTextureId, bool isAnimatedImage, uint32_t frameIndex );
763
764   /**
765    * @brief Looks up a cached texture by its hash.
766    * If found, the given parameters are used to check there is no hash-collision.
767    * @param[in] hash              The hash to look up
768    * @param[in] url               The URL of the image to load
769    * @param[in] size              The image size
770    * @param[in] fittingMode       The FittingMode to use
771    * @param[in] samplingMode      The SamplingMode to use
772    * @param[in] useAtlas          True if atlased
773    * @param[in] maskTextureId     Optional texture ID to use to mask this image
774    * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
775    * @param[in] isAnimatedImage   The boolean value to know whether the request is for animated image or not
776    * @param[in] frameIndex        The frame index of a frame to be loaded frame
777    * @return                      A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
778    */
779   TextureManager::TextureId FindCachedTexture(
780     const TextureManager::TextureHash hash,
781     const std::string& url,
782     const ImageDimensions size,
783     const FittingMode::Type fittingMode,
784     const Dali::SamplingMode::Type samplingMode,
785     const bool useAtlas,
786     TextureId maskTextureId,
787     MultiplyOnLoad preMultiplyOnLoad,
788     bool isAnimatedImage,
789     uint32_t frameIndex );
790
791 private:
792
793   /**
794    * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
795    */
796   class AsyncLoadingHelper : public ConnectionTracker
797   {
798   public:
799     /**
800      * @brief Create an AsyncLoadingHelper.
801      * @param[in] textureManager Reference to the texture manager
802      */
803     AsyncLoadingHelper(TextureManager& textureManager);
804
805     /**
806      * @brief Load a new frame of animated image
807      * @param[in] textureId             TextureId to reference the texture that will be loaded
808      * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
809      * @param[in] frameIndex            The frame index of a frame to be loaded frame
810      */
811     void LoadAnimatedImage( TextureId textureId,
812                             Dali::AnimatedImageLoading animatedImageLoading,
813                             uint32_t frameIndex);
814
815     /**
816      * @brief Load a new texture.
817      * @param[in] textureId             TextureId to reference the texture that will be loaded
818      * @param[in] url                   The URL of the image to load
819      * @param[in] desiredSize           The size the image is likely to appear at.
820      *                                  This can be set to 0,0 for automatic
821      * @param[in] fittingMode           The FittingMode to use
822      * @param[in] samplingMode          The SamplingMode to use
823      * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
824      *                                  e.g., from portrait to landscape
825      * @param[in] preMultiplyOnLoad     if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
826      */
827     void Load(TextureId textureId,
828               const VisualUrl& url,
829               ImageDimensions desiredSize,
830               FittingMode::Type fittingMode,
831               SamplingMode::Type samplingMode,
832               bool orientationCorrection,
833               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
834
835     /**
836      * @brief Apply mask
837      * @param [in] id of the texture
838      * @param [in] pixelBuffer of the to be masked image
839      * @param [in] maskPixelBuffer of the mask image
840      * @param [in] contentScale The factor to scale the content
841      * @param [in] cropToMask Whether to crop the content to the mask size
842      * @param [in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
843      */
844     void ApplyMask( TextureId textureId,
845                     Devel::PixelBuffer pixelBuffer,
846                     Devel::PixelBuffer maskPixelBuffer,
847                     float contentScale,
848                     bool cropToMask,
849                     DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
850
851   public:
852     AsyncLoadingHelper(const AsyncLoadingHelper&) = delete;
853     AsyncLoadingHelper& operator=(const AsyncLoadingHelper&) = delete;
854
855     AsyncLoadingHelper(AsyncLoadingHelper&& rhs);
856     AsyncLoadingHelper& operator=(AsyncLoadingHelper&&rhs) = delete;
857
858   private:
859     /**
860      * @brief Main constructor that used by all other constructors
861      */
862     AsyncLoadingHelper( Toolkit::AsyncImageLoader loader,
863                         TextureManager& textureManager,
864                         AsyncLoadingInfoContainerType&& loadingInfoContainer );
865
866     /**
867      * @brief Callback to be called when texture loading is complete, it passes the pixel buffer on to texture manager.
868      * @param[in] id          Loader id
869      * @param[in] pixelBuffer Image data
870      */
871     void AsyncLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
872
873   private:
874     Toolkit::AsyncImageLoader     mLoader;
875     TextureManager&               mTextureManager;
876     AsyncLoadingInfoContainerType mLoadingInfoContainer;
877   };
878
879   struct ExternalTextureInfo
880   {
881     TextureId textureId;
882     TextureSet textureSet;
883   };
884
885 private:
886
887   /**
888    * Deleted copy constructor.
889    */
890   TextureManager( const TextureManager& ) = delete;
891
892   /**
893    * Deleted assignment operator.
894    */
895   TextureManager& operator=( const TextureManager& rhs ) = delete;
896
897   /**
898    * This is called by the TextureManagerUploadObserver when an observer is destroyed.
899    * We use the callback to know when to remove an observer from our notify list.
900    * @param[in] observer The observer that generated the callback
901    */
902   void ObserverDestroyed( TextureUploadObserver* observer );
903
904 private:  // Member Variables:
905
906   TextureInfoContainerType                      mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
907   RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders;    ///< The Asynchronous image loaders used to provide all local async loads
908   RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders;   ///< The Asynchronous image loaders used to provide all remote async loads
909   std::vector< ExternalTextureInfo >            mExternalTextures;     ///< Externally provided textures
910   Dali::Vector<LifecycleObserver*>              mLifecycleObservers;   ///< Lifecycle observers of texture manager
911   Dali::Vector<LoadQueueElement>                mLoadQueue;            ///< Queue of textures to load after NotifyObservers
912   std::string                                   mBrokenImageUrl;       ///< Broken image url
913   TextureId                                     mCurrentTextureId;     ///< The current value used for the unique Texture Id generation
914   bool                                          mQueueLoadFlag;        ///< Flag that causes Load Textures to be queued.
915 };
916
917
918 } // name Internal
919
920 } // namespace Toolkit
921
922 } // namespace Dali
923
924 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H