Add multiple thread support to TextureManager
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / texture-manager.h
index 04faf46..090846e 100644 (file)
  */
 
 // EXTERNAL INCLUDES
+#include <deque>
+#include <functional>
 #include <string>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/rendering/texture-set.h>
 #include <dali/devel-api/common/owner-container.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <deque>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
 
 
 namespace Dali
@@ -150,21 +154,26 @@ public:
    * When the client has finished with the Texture, Remove() should be called.
    *
    * @param[in] url               The URL of the image to load
+   * @param[in] maskTextureId     The texture id of an image to mask this with (can be INVALID if no masking required)
+   * @param[in] contentScale      The scale factor to apply to the image before masking
    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
    * @param[in] fittingMode       The FittingMode to use
    * @param[in] samplingMode      The SamplingMode to use
    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] cropToMask        Only used with masking, this will crop the scaled image to the mask size. If false, then the mask will be scaled to fit the image before being applied.
    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
    *                              This is called when an image load completes (or fails).
    * @return                      A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoad( const VisualUrl&         url,
                          TextureId                maskTextureId,
+                         float                    contentScale,
                          const ImageDimensions    desiredSize,
                          FittingMode::Type        fittingMode,
                          Dali::SamplingMode::Type samplingMode,
                          const UseAtlas           useAtlasing,
+                         bool                     cropToMask,
                          TextureUploadObserver*   observer );
 
   /**
@@ -217,11 +226,13 @@ private:
    *
    * @param[in] url               The URL of the image to load
    * @param[in] maskTextureId     The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
+   * @param[in] contentScale      The scaling factor to apply to the content when masking
    * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
    * @param[in] fittingMode       The FittingMode to use
    * @param[in] samplingMode      The SamplingMode to use
    * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
    *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] cropToMask        Whether to crop the target after masking, or scale the mask to the image before masking.
    * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
    * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
    *                              This is called when an image load completes (or fails).
@@ -230,10 +241,12 @@ private:
   TextureId RequestLoadInternal(
     const VisualUrl&         url,
     TextureId                maskTextureId,
+    float                    contentScale,
     const ImageDimensions    desiredSize,
     FittingMode::Type        fittingMode,
     Dali::SamplingMode::Type samplingMode,
     UseAtlas                 useAtlas,
+    bool                     cropToMask,
     StorageType              storageType,
     TextureUploadObserver*   observer );
 
@@ -249,9 +262,11 @@ private:
                  TextureId maskTextureId,
                  const VisualUrl& url,
                  ImageDimensions desiredSize,
+                 float scaleFactor,
                  FittingMode::Type fittingMode,
                  Dali::SamplingMode::Type samplingMode,
                  bool loadSynchronously,
+                 bool cropToMask,
                  UseAtlas useAtlas,
                  TextureManager::TextureHash hash )
     : url( url ),
@@ -261,13 +276,15 @@ private:
       textureId( textureId ),
       maskTextureId( maskTextureId ),
       hash( hash ),
+      scaleFactor( scaleFactor ),
       referenceCount( 1u ),
       loadState( NOT_STARTED ),
       fittingMode( fittingMode ),
       samplingMode( samplingMode ),
       storageType( UPLOAD_TO_TEXTURE ),
       loadSynchronously( loadSynchronously ),
-      useAtlas( useAtlas )
+      useAtlas( useAtlas ),
+      cropToMask( cropToMask )
     {
     }
 
@@ -287,6 +304,7 @@ private:
     TextureId textureId;           ///< The TextureId associated with this Texture
     TextureId maskTextureId;       ///< The mask TextureId to be applied on load
     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
+    float scaleFactor;             ///< The scale factor to apply to the Texture when masking
     int16_t referenceCount;        ///< The reference count of clients using this Texture
     LoadState loadState:3;         ///< The load state showing the load progress of the Texture
     FittingMode::Type fittingMode:2; ///< The requested FittingMode
@@ -294,6 +312,7 @@ private:
     StorageType storageType:1;     ///< CPU storage / GPU upload;
     bool loadSynchronously:1;      ///< True if synchronous loading was requested
     UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
+    bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
   };
 
   // Structs:
@@ -390,8 +409,11 @@ private:
    * Apply the mask to the pixelBuffer.
    * @param[in] pixelBuffer The pixelBuffer to apply the mask to
    * @param[in] maskTextureId The texture id of the mask.
+   * @param[in] contentScale The factor to scale the content
+   * @param[in] cropToMask Whether to crop the content to the mask size
    */
-  void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId );
+  void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId,
+                  float contentScale, bool cropToMask );
 
   /**
    * Upload the texture specified in pixelBuffer to the appropriate location
@@ -446,7 +468,6 @@ private:
                             const FittingMode::Type fittingMode,
                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
                             TextureId maskTextureId );
-
   /**
    * @brief Looks up a cached texture by its hash.
    * If found, the given parameters are used to check there is no hash-collision.
@@ -468,18 +489,75 @@ private:
     const bool useAtlas,
     TextureId maskTextureId );
 
+private:
+
+  /**
+   * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
+   */
+  class AsyncLoadingHelper : public ConnectionTracker
+  {
+  public:
+    /**
+     * @brief Create an AsyncLoadingHelper.
+     * @param[in] textureManager Reference to the texture manager
+     */
+    AsyncLoadingHelper(TextureManager& textureManager);
+
+    /**
+     * @brief Load a new texture.
+     * @param[in] textureId             TextureId to reference the texture that will be loaded
+     * @param[in] url                   The URL of the image to load
+     * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+     * @param[in] fittingMode           The FittingMode to use
+     * @param[in] samplingMode          The SamplingMode to use
+     * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image, e.g., from portrait to landscape
+     */
+    void Load(TextureId textureId,
+              const VisualUrl& url,
+              ImageDimensions desiredSize,
+              FittingMode::Type fittingMode,
+              SamplingMode::Type samplingMode,
+              bool orientationCorrection);
+
+  public:
+    AsyncLoadingHelper(const AsyncLoadingHelper&) = delete;
+    AsyncLoadingHelper& operator=(const AsyncLoadingHelper&) = delete;
+
+    AsyncLoadingHelper(AsyncLoadingHelper&& rhs);
+    AsyncLoadingHelper& operator=(AsyncLoadingHelper&&rhs) = delete;
+
+  private:
+    /**
+     * @brief Main constructor that used by all other constructors
+     */
+    AsyncLoadingHelper(Toolkit::AsyncImageLoader loader,
+                       TextureManager& textureManager,
+                       AsyncLoadingInfoContainerType&& loadingInfoContainer);
+
+    /**
+     * @brief Callback to be called when texture loading is complete, it passes the pixel buffer on to texture manager.
+     * @param[in] id          Loader id
+     * @param[in] pixelBuffer Image data
+     */
+    void AsyncLoadComplete(uint32_t id, Devel::PixelBuffer pixelBuffer);
+
+  private:
+    Toolkit::AsyncImageLoader     mLoader;
+    TextureManager&               mTextureManager;
+    AsyncLoadingInfoContainerType mLoadingInfoContainer;
+  };
 
 private:
 
   /**
-   * Undefined copy constructor.
+   * Deleted copy constructor.
    */
-  TextureManager( const TextureManager& );
+  TextureManager( const TextureManager& ) = delete;
 
   /**
-   * Undefined assignment operator.
+   * Deleted assignment operator.
    */
-  TextureManager& operator=( const TextureManager& rhs );
+  TextureManager& operator=( const TextureManager& rhs ) = delete;
 
   /**
    * This is called by the TextureManagerUploadObserver when an observer is destroyed.
@@ -490,14 +568,12 @@ private:
 
 private:  // Member Variables:
 
-  AsyncLoadingInfoContainerType         mAsyncLocalLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
-  AsyncLoadingInfoContainerType         mAsyncRemoteLoadingInfoContainer;     ///< Used to manage Asynchronous loads in progress
-  AtlasInfoContainerType                mAtlasContainer;                ///< Used to manage Atlas creation and destruction
-  TextureInfoContainerType              mTextureInfoContainer;          ///< Used to manage the life-cycle and caching of Textures
-  Toolkit::AsyncImageLoader             mAsyncLocalLoader;              ///< The Asynchronous image loader used to provide all local async loads
-  Toolkit::AsyncImageLoader             mAsyncRemoteLoader;             ///< The Asynchronous image loader used to provide all remote async loads
-  TextureId                             mCurrentTextureId;              ///< The current value used for the unique Texture Id generation
+  AtlasInfoContainerType        mAtlasContainer;                  ///< Used to manage Atlas creation and destruction
+  TextureInfoContainerType      mTextureInfoContainer;            ///< Used to manage the life-cycle and caching of Textures
+  TextureId                     mCurrentTextureId;                ///< The current value used for the unique Texture Id generation
 
+  RoundRobinContainerView<AsyncLoadingHelper> mAsyncLocalLoaders;  ///< The Asynchronous image loaders used to provide all local async loads
+  RoundRobinContainerView<AsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
 };