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