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