1 #ifndef DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
2 #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
5 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <dali/public-api/common/dali-vector.h>
26 #include <dali/public-api/object/ref-object.h>
27 #include <dali/public-api/rendering/texture-set.h>
28 #include <dali/devel-api/common/owner-container.h>
29 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
32 #include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
33 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
34 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
35 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
36 #include <dali-toolkit/internal/visuals/visual-url.h>
37 #include <dali-toolkit/internal/helpers/round-robin-container-view.h>
38 #include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
49 class ImageAtlasManager;
50 typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
53 * The TextureManager provides a common Image loading API for Visuals.
55 * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
56 * Texture caching is provided and performed when possible.
57 * Broken Images are automatically provided on load failure.
59 class TextureManager : public ConnectionTracker
63 typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
64 static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
67 * Whether the texture should be atlased or uploaded into it's own GPU texture
76 * Whether the pixel data should be kept in TextureManager, or uploaded for rendering
85 * Whether the texture should be loaded synchronously or asynchronously.
94 * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
98 NOT_STARTED, ///< Default
99 LOADING, ///< Loading has been started, but not finished.
100 LOAD_FINISHED, ///< Loading has finished. (for CPU storage only)
101 WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
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
112 ~MaskingData() = default;
114 VisualUrl mAlphaMaskUrl;
115 TextureManager::TextureId mAlphaMaskId;
116 float mContentScaleFactor;
119 using MaskingDataPointer = std::unique_ptr<MaskingData>;
129 ~TextureManager() = default;
132 // TextureManager Main API:
134 TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize,
135 Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
136 const MaskingDataPointer& maskInfo, bool synchronousLoading,
137 TextureManager::TextureId& textureId, Vector4& textureRect,
138 bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
139 Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
140 AtlasUploadObserver* atlasObserver,
141 ImageAtlasManagerPtr imageAtlasManager,
142 bool orientationCorrection );
145 * @brief Requests an image load of the given URL.
147 * The parameters are used to specify how the image is loaded.
148 * The observer has the UploadComplete method called when the load is ready.
150 * When the client has finished with the Texture, Remove() should be called.
152 * @param[in] url The URL of the image to load
153 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
154 * @param[in] fittingMode The FittingMode to use
155 * @param[in] samplingMode The SamplingMode to use
156 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
157 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
158 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
159 * This is called when an image load completes (or fails).
160 * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
161 * @return A TextureId to use as a handle to reference this Texture
163 TextureId RequestLoad( const VisualUrl& url,
164 const ImageDimensions desiredSize,
165 FittingMode::Type fittingMode,
166 Dali::SamplingMode::Type samplingMode,
167 const UseAtlas useAtlasing,
168 TextureUploadObserver* observer,
169 bool orientationCorrection );
172 * @brief Requests an image load of the given URL, when the texture has
173 * have loaded, it will perform a blend with the image mask, and upload
174 * the blended texture.
176 * The parameters are used to specify how the image is loaded.
177 * The observer has the UploadComplete method called when the load is ready.
179 * When the client has finished with the Texture, Remove() should be called.
181 * @param[in] url The URL of the image to load
182 * @param[in] maskTextureId The texture id of an image to mask this with (can be INVALID if no masking required)
183 * @param[in] contentScale The scale factor to apply to the image before masking
184 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
185 * @param[in] fittingMode The FittingMode to use
186 * @param[in] samplingMode The SamplingMode to use
187 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
188 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
189 * @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.
190 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
191 * This is called when an image load completes (or fails).
192 * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
193 * @return A TextureId to use as a handle to reference this Texture
195 TextureId RequestLoad( const VisualUrl& url,
196 TextureId maskTextureId,
198 const ImageDimensions desiredSize,
199 FittingMode::Type fittingMode,
200 Dali::SamplingMode::Type samplingMode,
201 const UseAtlas useAtlasing,
203 TextureUploadObserver* observer,
204 bool orientationCorrection );
207 * Requests a masking image to be loaded. This mask is not uploaded to GL,
208 * instead, it is stored in CPU memory, and can be used for CPU blending.
210 TextureId RequestMaskLoad( const VisualUrl& maskUrl );
213 * @brief Remove a Texture from the TextureManager.
215 * Textures are cached and therefore only the removal of the last
216 * occurrence of a Texture will cause its removal internally.
218 * @param[in] textureId The ID of the Texture to remove.
220 void Remove( const TextureManager::TextureId textureId );
223 * Get the visualUrl associated with the texture id
225 const VisualUrl& GetVisualUrl( TextureId textureId );
228 * @brief Get the current state of a texture
229 * @param[in] textureId The texture id to query
230 * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
233 LoadState GetTextureState( TextureId textureId );
236 * @brief Get the associated texture set if the texture id is valid
237 * @param[in] textureId The texture Id to look up
238 * @return the associated texture set, or an empty handle if textureId is not valid
240 TextureSet GetTextureSet( TextureId textureId );
243 * Adds an external texture to the texture manager
244 * @param[in] texture The texture to add
245 * @return string containing the URL for the texture
247 std::string AddExternalTexture( TextureSet& texture );
250 * Removes an external texture from texture manager
251 * @param[in] url The string containing the texture to remove
252 * @return handle to the texture
254 TextureSet RemoveExternalTexture( const std::string& url );
259 * @brief Requests an image load of the given URL, when the texture has
260 * have loaded, if there is a valid maskTextureId, it will perform a
261 * CPU blend with the mask, and upload the blend texture.
263 * The parameters are used to specify how the image is loaded.
264 * The observer has the UploadComplete method called when the load is ready.
266 * When the client has finished with the Texture, Remove() should be called.
268 * @param[in] url The URL of the image to load
269 * @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
270 * @param[in] contentScale The scaling factor to apply to the content when masking
271 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
272 * @param[in] fittingMode The FittingMode to use
273 * @param[in] samplingMode The SamplingMode to use
274 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
275 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
276 * @param[in] cropToMask Whether to crop the target after masking, or scale the mask to the image before masking.
277 * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
278 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
279 * This is called when an image load completes (or fails).
280 * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
281 * @return A TextureId to use as a handle to reference this Texture
283 TextureId RequestLoadInternal(
284 const VisualUrl& url,
285 TextureId maskTextureId,
287 const ImageDimensions desiredSize,
288 FittingMode::Type fittingMode,
289 Dali::SamplingMode::Type samplingMode,
292 StorageType storageType,
293 TextureUploadObserver* observer,
294 bool orientationCorrection );
297 typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
300 * @brief This struct is used to manage the life-cycle of Texture loading and caching.
304 TextureInfo( TextureId textureId,
305 TextureId maskTextureId,
306 const VisualUrl& url,
307 ImageDimensions desiredSize,
309 FittingMode::Type fittingMode,
310 Dali::SamplingMode::Type samplingMode,
311 bool loadSynchronously,
314 TextureManager::TextureHash hash,
315 bool orientationCorrection )
317 desiredSize( desiredSize ),
318 useSize( desiredSize ),
319 atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
320 textureId( textureId ),
321 maskTextureId( maskTextureId ),
323 scaleFactor( scaleFactor ),
324 referenceCount( 1u ),
325 loadState( NOT_STARTED ),
326 fittingMode( fittingMode ),
327 samplingMode( samplingMode ),
328 storageType( UPLOAD_TO_TEXTURE ),
329 loadSynchronously( loadSynchronously ),
330 useAtlas( useAtlas ),
331 cropToMask( cropToMask ),
332 orientationCorrection( true )
337 * Container type used to store all observer clients of this Texture
339 typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
341 ObserverListType observerList; ///< Container used to store all observer clients of this Texture
342 Toolkit::ImageAtlas atlas; ///< The atlas this Texture lays within (if any)
343 Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
344 TextureSet textureSet; ///< The TextureSet holding the Texture
345 VisualUrl url; ///< The URL of the image
346 ImageDimensions desiredSize; ///< The size requested
347 ImageDimensions useSize; ///< The size used
348 Vector4 atlasRect; ///< The atlas rect used if atlased
349 TextureId textureId; ///< The TextureId associated with this Texture
350 TextureId maskTextureId; ///< The mask TextureId to be applied on load
351 TextureManager::TextureHash hash; ///< The hash used to cache this Texture
352 float scaleFactor; ///< The scale factor to apply to the Texture when masking
353 int16_t referenceCount; ///< The reference count of clients using this Texture
354 LoadState loadState:3; ///< The load state showing the load progress of the Texture
355 FittingMode::Type fittingMode:2; ///< The requested FittingMode
356 Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
357 StorageType storageType:1; ///< CPU storage / GPU upload;
358 bool loadSynchronously:1; ///< True if synchronous loading was requested
359 UseAtlas useAtlas:1; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
360 bool cropToMask:1; ///< true if the image should be cropped to the mask size.
361 bool orientationCorrection:1; ///< true if the image should be rotated to match exif orientation data
367 * Struct to hold information about a requested Async load.
368 * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
370 struct AsyncLoadingInfo
372 AsyncLoadingInfo( TextureId textureId )
373 : textureId( textureId ),
378 TextureId textureId; ///< The external Texture Id assigned to this load
379 unsigned short loadId; ///< The load Id used by the async loader to reference this load
384 typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
385 typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
388 * @brief Used internally to initiate a load.
389 * @param[in] textureInfo The TextureInfo struct associated with the Texture
390 * @return True if the load was initiated
392 bool LoadTexture( TextureInfo& textureInfo );
395 * Add the observer to the observer list
396 * @param[in] textureInfo The TextureInfo struct associated with the texture
397 * observer The observer wishing to observe the texture upload
399 void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
402 * @brief This signal handler is called when the async local loader finishes loading.
403 * @param[in] id This is the async image loaders Id
404 * @param[in] pixelBuffer The loaded image data
406 void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
409 * @brief This signal handler is called when the async local loader finishes loading.
410 * @param[in] id This is the async image loaders Id
411 * @param[in] pixelBuffer The loaded image data
413 void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
416 * Common method to handle loading completion
417 * @param[in] container The Async loading container
418 * @param[in] id This is the async image loaders Id
419 * @param[in] pixelBuffer The loaded image data
421 void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
424 * @brief Performs Post-Load steps including atlasing.
425 * @param[in] textureInfo The struct associated with this Texture
426 * @param[in] pixelBuffer The image pixelBuffer
427 * @return True if successful
429 void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
432 * Check if there is a texture waiting to be masked. If there
433 * is then apply this mask and upload it.
434 * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
436 void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
439 * Apply the mask to the pixelBuffer.
440 * @param[in] pixelBuffer The pixelBuffer to apply the mask to
441 * @param[in] maskTextureId The texture id of the mask.
442 * @param[in] contentScale The factor to scale the content
443 * @param[in] cropToMask Whether to crop the content to the mask size
445 void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId,
446 float contentScale, bool cropToMask );
449 * Upload the texture specified in pixelBuffer to the appropriate location
450 * @param[in] pixelBuffer The image data to upload
451 * @param[in] textureInfo The texture info containing the location to
454 void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
457 * Mark the texture as complete, and inform observers
458 * @param[in] textureInfo The struct associated with this Texture
460 void UploadComplete( TextureInfo& textureInfo );
463 * Notify the current observers that the texture upload is complete,
464 * then remove the observers from the list.
465 * @param[in] textureInfo The struct associated with this Texture
466 * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
468 void NotifyObservers( TextureInfo& textureInfo, bool success );
471 * @brief Generates a new, unique TextureId
472 * @return A unique TextureId
474 TextureManager::TextureId GenerateUniqueTextureId();
477 * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
478 * @param[in] textureId The TextureId to look up
479 * @return The cache index
481 int GetCacheIndexFromId( TextureId textureId );
485 * @brief Generates a hash for caching based on the input parameters.
486 * Only applies size, fitting mode andsampling mode if the size is specified.
487 * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
488 * Always applies useAtlas.
489 * @param[in] url The URL of the image to load
490 * @param[in] size The image size
491 * @param[in] fittingMode The FittingMode to use
492 * @param[in] samplingMode The SamplingMode to use
493 * @param[in] useAtlas True if atlased
494 * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
495 * @return A hash of the provided data for caching.
497 TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
498 const FittingMode::Type fittingMode,
499 const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
500 TextureId maskTextureId );
502 * @brief Looks up a cached texture by its hash.
503 * If found, the given parameters are used to check there is no hash-collision.
504 * @param[in] hash The hash to look up
505 * @param[in] url The URL of the image to load
506 * @param[in] size The image size
507 * @param[in] fittingMode The FittingMode to use
508 * @param[in] samplingMode The SamplingMode to use
509 * @param[in] useAtlas True if atlased
510 * @param[in] maskTextureId Optional texture ID to use to mask this image
511 * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
513 TextureManager::TextureId FindCachedTexture(
514 const TextureManager::TextureHash hash,
515 const std::string& url,
516 const ImageDimensions size,
517 const FittingMode::Type fittingMode,
518 const Dali::SamplingMode::Type samplingMode,
520 TextureId maskTextureId );
525 * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
527 class AsyncLoadingHelper : public ConnectionTracker
531 * @brief Create an AsyncLoadingHelper.
532 * @param[in] textureManager Reference to the texture manager
534 AsyncLoadingHelper(TextureManager& textureManager);
537 * @brief Load a new texture.
538 * @param[in] textureId TextureId to reference the texture that will be loaded
539 * @param[in] url The URL of the image to load
540 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
541 * @param[in] fittingMode The FittingMode to use
542 * @param[in] samplingMode The SamplingMode to use
543 * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image, e.g., from portrait to landscape
545 void Load(TextureId textureId,
546 const VisualUrl& url,
547 ImageDimensions desiredSize,
548 FittingMode::Type fittingMode,
549 SamplingMode::Type samplingMode,
550 bool orientationCorrection);
553 AsyncLoadingHelper(const AsyncLoadingHelper&) = delete;
554 AsyncLoadingHelper& operator=(const AsyncLoadingHelper&) = delete;
556 AsyncLoadingHelper(AsyncLoadingHelper&& rhs);
557 AsyncLoadingHelper& operator=(AsyncLoadingHelper&&rhs) = delete;
561 * @brief Main constructor that used by all other constructors
563 AsyncLoadingHelper(Toolkit::AsyncImageLoader loader,
564 TextureManager& textureManager,
565 AsyncLoadingInfoContainerType&& loadingInfoContainer);
568 * @brief Callback to be called when texture loading is complete, it passes the pixel buffer on to texture manager.
569 * @param[in] id Loader id
570 * @param[in] pixelBuffer Image data
572 void AsyncLoadComplete(uint32_t id, Devel::PixelBuffer pixelBuffer);
575 Toolkit::AsyncImageLoader mLoader;
576 TextureManager& mTextureManager;
577 AsyncLoadingInfoContainerType mLoadingInfoContainer;
580 struct ExternalTextureInfo
583 TextureSet textureSet;
589 * Deleted copy constructor.
591 TextureManager( const TextureManager& ) = delete;
594 * Deleted assignment operator.
596 TextureManager& operator=( const TextureManager& rhs ) = delete;
599 * This is called by the TextureManagerUploadObserver when an observer is destroyed.
600 * We use the callback to know when to remove an observer from our notify list.
601 * @param[in] observer The observer that generated the callback
603 void ObserverDestroyed( TextureUploadObserver* observer );
605 private: // Member Variables:
607 TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
608 RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
609 RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
610 std::vector< ExternalTextureInfo > mExternalTextures; ///< Externally provided textures
611 TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
618 } // namespace Toolkit
622 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H