1 #ifndef DALI_TOOLKIT_TEXTURE_MANAGER_H
2 #define DALI_TOOLKIT_TEXTURE_MANAGER_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.
22 #include <dali/public-api/common/dali-vector.h>
23 #include <dali/public-api/object/ref-object.h>
24 #include <dali/public-api/rendering/texture-set.h>
25 #include <dali/devel-api/common/owner-container.h>
26 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
30 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
31 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
32 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
33 #include <dali-toolkit/internal/visuals/visual-url.h>
45 class MaskTextureObserver;
48 * The TextureManager provides a common Image loading API for Visuals.
50 * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
51 * Texture caching is provided and performed when possible.
52 * Broken Images are automatically provided on load failure.
54 class TextureManager : public ConnectionTracker
58 typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
59 static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
62 * Whether the texture should be atlased or uploaded into it's own GPU texture
71 * Whether the pixel data should be kept in TextureManager, or uploaded for rendering
80 * Whether the texture should be loaded synchronously or asynchronously.
89 * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
93 NOT_STARTED, ///< Default
94 LOADING, ///< Loading has been started, but not finished.
95 LOAD_FINISHED, ///< Loading has finished. (for CPU storage only)
96 WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
97 UPLOADED, ///< Uploaded and ready. (For GPU upload only)
98 CANCELLED, ///< Removed before loading completed
99 LOAD_FAILED ///< Async loading failed, e.g. connection problem
115 // TextureManager Main API:
118 * @brief Requests an image load of the given URL.
120 * The parameters are used to specify how the image is loaded.
121 * The observer has the UploadComplete method called when the load is ready.
123 * When the client has finished with the Texture, Remove() should be called.
125 * @param[in] url The URL of the image to load
126 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
127 * @param[in] fittingMode The FittingMode to use
128 * @param[in] samplingMode The SamplingMode to use
129 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
130 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
131 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
132 * This is called when an image load completes (or fails).
133 * @return A TextureId to use as a handle to reference this Texture
135 TextureId RequestLoad( const VisualUrl& url,
136 const ImageDimensions desiredSize,
137 FittingMode::Type fittingMode,
138 Dali::SamplingMode::Type samplingMode,
139 const UseAtlas useAtlasing,
140 TextureUploadObserver* observer );
143 * @brief Requests an image load of the given URL, when the texture has
144 * have loaded, it will perform a blend with the image mask, and upload
145 * the blended texture.
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] maskTextureId The texture id of an image to mask this with (can be INVALID if no masking required)
154 * @param[in] contentScale The scale factor to apply to the image before masking
155 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
156 * @param[in] fittingMode The FittingMode to use
157 * @param[in] samplingMode The SamplingMode to use
158 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
159 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
160 * @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.
161 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
162 * This is called when an image load completes (or fails).
163 * @return A TextureId to use as a handle to reference this Texture
165 TextureId RequestLoad( const VisualUrl& url,
166 TextureId maskTextureId,
168 const ImageDimensions desiredSize,
169 FittingMode::Type fittingMode,
170 Dali::SamplingMode::Type samplingMode,
171 const UseAtlas useAtlasing,
173 TextureUploadObserver* observer );
176 * Requests a masking image to be loaded. This mask is not uploaded to GL,
177 * instead, it is stored in CPU memory, and can be used for CPU blending.
179 TextureId RequestMaskLoad( const VisualUrl& maskUrl );
182 * @brief Remove a Texture from the TextureManager.
184 * Textures are cached and therefore only the removal of the last
185 * occurrence of a Texture will cause its removal internally.
187 * @param[in] textureId The ID of the Texture to remove.
189 void Remove( const TextureManager::TextureId textureId );
192 * Get the visualUrl associated with the texture id
194 const VisualUrl& GetVisualUrl( TextureId textureId );
197 * @brief Get the current state of a texture
198 * @param[in] textureId The texture id to query
199 * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
202 LoadState GetTextureState( TextureId textureId );
205 * @brief Get the associated texture set if the texture id is valid
206 * @param[in] textureId The texture Id to look up
207 * @return the associated texture set, or an empty handle if textureId is not valid
209 TextureSet GetTextureSet( TextureId textureId );
214 * @brief Requests an image load of the given URL, when the texture has
215 * have loaded, if there is a valid maskTextureId, it will perform a
216 * CPU blend with the mask, and upload the blend texture.
218 * The parameters are used to specify how the image is loaded.
219 * The observer has the UploadComplete method called when the load is ready.
221 * When the client has finished with the Texture, Remove() should be called.
223 * @param[in] url The URL of the image to load
224 * @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
225 * @param[in] contentScale The scaling factor to apply to the content when masking
226 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
227 * @param[in] fittingMode The FittingMode to use
228 * @param[in] samplingMode The SamplingMode to use
229 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
230 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
231 * @param[in] cropToMask Whether to crop the target after masking, or scale the mask to the image before masking.
232 * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
233 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
234 * This is called when an image load completes (or fails).
235 * @return A TextureId to use as a handle to reference this Texture
237 TextureId RequestLoadInternal(
238 const VisualUrl& url,
239 TextureId maskTextureId,
241 const ImageDimensions desiredSize,
242 FittingMode::Type fittingMode,
243 Dali::SamplingMode::Type samplingMode,
246 StorageType storageType,
247 TextureUploadObserver* observer );
250 typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
253 * @brief This struct is used to manage the life-cycle of Texture loading and caching.
257 TextureInfo( TextureId textureId,
258 TextureId maskTextureId,
259 const VisualUrl& url,
260 ImageDimensions desiredSize,
262 FittingMode::Type fittingMode,
263 Dali::SamplingMode::Type samplingMode,
264 bool loadSynchronously,
267 TextureManager::TextureHash hash )
269 desiredSize( desiredSize ),
270 useSize( desiredSize ),
271 atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
272 textureId( textureId ),
273 maskTextureId( maskTextureId ),
275 scaleFactor( scaleFactor ),
276 referenceCount( 1u ),
277 loadState( NOT_STARTED ),
278 fittingMode( fittingMode ),
279 samplingMode( samplingMode ),
280 storageType( UPLOAD_TO_TEXTURE ),
281 loadSynchronously( loadSynchronously ),
282 useAtlas( useAtlas ),
283 cropToMask( cropToMask )
288 * Container type used to store all observer clients of this Texture
290 typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
292 ObserverListType observerList; ///< Container used to store all observer clients of this Texture
293 Toolkit::ImageAtlas atlas; ///< The atlas this Texture lays within (if any)
294 Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
295 TextureSet textureSet; ///< The TextureSet holding the Texture
296 VisualUrl url; ///< The URL of the image
297 ImageDimensions desiredSize; ///< The size requested
298 ImageDimensions useSize; ///< The size used
299 Vector4 atlasRect; ///< The atlas rect used if atlased
300 TextureId textureId; ///< The TextureId associated with this Texture
301 TextureId maskTextureId; ///< The mask TextureId to be applied on load
302 TextureManager::TextureHash hash; ///< The hash used to cache this Texture
303 float scaleFactor; ///< The scale factor to apply to the Texture when masking
304 int16_t referenceCount; ///< The reference count of clients using this Texture
305 LoadState loadState:3; ///< The load state showing the load progress of the Texture
306 FittingMode::Type fittingMode:2; ///< The requested FittingMode
307 Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
308 StorageType storageType:1; ///< CPU storage / GPU upload;
309 bool loadSynchronously:1; ///< True if synchronous loading was requested
310 UseAtlas useAtlas:1; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
311 bool cropToMask:1; ///< true if the image should be cropped to the mask size.
317 * Struct to hold information about a requested Async load.
318 * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
320 struct AsyncLoadingInfo
322 AsyncLoadingInfo( TextureId textureId )
323 : textureId( textureId ),
328 TextureId textureId; ///< The external Texture Id assigned to this load
329 unsigned short loadId; ///< The load Id used by the async loader to reference this load
333 * @brief This struct is used within a container to manage atlas creation and destruction.
337 AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
339 textureSet( textureSet )
343 Toolkit::ImageAtlas atlas; ///< The ImageAtlas object
344 TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
349 typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
350 typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
351 typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
354 * @brief Used internally to initiate a load.
355 * @param[in] textureInfo The TextureInfo struct associated with the Texture
356 * @return True if the load was initiated
358 bool LoadTexture( TextureInfo& textureInfo );
361 * Add the observer to the observer list
362 * @param[in] textureInfo The TextureInfo struct associated with the texture
363 * observer The observer wishing to observe the texture upload
365 void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
368 * @brief This signal handler is called when the async local loader finishes loading.
369 * @param[in] id This is the async image loaders Id
370 * @param[in] pixelBuffer The loaded image data
372 void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
375 * @brief This signal handler is called when the async local loader finishes loading.
376 * @param[in] id This is the async image loaders Id
377 * @param[in] pixelBuffer The loaded image data
379 void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
382 * Common method to handle loading completion
383 * @param[in] container The Async loading container
384 * @param[in] id This is the async image loaders Id
385 * @param[in] pixelBuffer The loaded image data
387 void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
390 * @brief Performs Post-Load steps including atlasing.
391 * @param[in] textureInfo The struct associated with this Texture
392 * @param[in] pixelBuffer The image pixelBuffer
393 * @return True if successful
395 void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
398 * Check if there is a texture waiting to be masked. If there
399 * is then apply this mask and upload it.
400 * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
402 void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
405 * Apply the mask to the pixelBuffer.
406 * @param[in] pixelBuffer The pixelBuffer to apply the mask to
407 * @param[in] maskTextureId The texture id of the mask.
408 * @param[in] contentScale The factor to scale the content
409 * @param[in] cropToMask Whether to crop the content to the mask size
411 void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId,
412 float contentScale, bool cropToMask );
415 * Upload the texture specified in pixelBuffer to the appropriate location
416 * @param[in] pixelBuffer The image data to upload
417 * @param[in] textureInfo The texture info containing the location to
420 void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
423 * Mark the texture as complete, and inform observers
424 * @param[in] textureInfo The struct associated with this Texture
426 void UploadComplete( TextureInfo& textureInfo );
429 * Notify the current observers that the texture upload is complete,
430 * then remove the observers from the list.
431 * @param[in] textureInfo The struct associated with this Texture
432 * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
434 void NotifyObservers( TextureInfo& textureInfo, bool success );
437 * @brief Generates a new, unique TextureId
438 * @return A unique TextureId
440 TextureManager::TextureId GenerateUniqueTextureId();
443 * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
444 * @param[in] textureId The TextureId to look up
445 * @return The cache index
447 int GetCacheIndexFromId( TextureId textureId );
451 * @brief Generates a hash for caching based on the input parameters.
452 * Only applies size, fitting mode andsampling mode if the size is specified.
453 * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
454 * Always applies useAtlas.
455 * @param[in] url The URL of the image to load
456 * @param[in] size The image size
457 * @param[in] fittingMode The FittingMode to use
458 * @param[in] samplingMode The SamplingMode to use
459 * @param[in] useAtlas True if atlased
460 * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
461 * @return A hash of the provided data for caching.
463 TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
464 const FittingMode::Type fittingMode,
465 const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
466 TextureId maskTextureId );
468 * @brief Looks up a cached texture by its hash.
469 * If found, the given parameters are used to check there is no hash-collision.
470 * @param[in] hash The hash to look up
471 * @param[in] url The URL of the image to load
472 * @param[in] size The image size
473 * @param[in] fittingMode The FittingMode to use
474 * @param[in] samplingMode The SamplingMode to use
475 * @param[in] useAtlas True if atlased
476 * @param[in] maskTextureId Optional texture ID to use to mask this image
477 * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
479 TextureManager::TextureId FindCachedTexture(
480 const TextureManager::TextureHash hash,
481 const std::string& url,
482 const ImageDimensions size,
483 const FittingMode::Type fittingMode,
484 const Dali::SamplingMode::Type samplingMode,
486 TextureId maskTextureId );
492 * Undefined copy constructor.
494 TextureManager( const TextureManager& );
497 * Undefined assignment operator.
499 TextureManager& operator=( const TextureManager& rhs );
502 * This is called by the TextureManagerUploadObserver when an observer is destroyed.
503 * We use the callback to know when to remove an observer from our notify list.
504 * @param[in] observer The observer that generated the callback
506 void ObserverDestroyed( TextureUploadObserver* observer );
508 private: // Member Variables:
510 AsyncLoadingInfoContainerType mAsyncLocalLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
511 AsyncLoadingInfoContainerType mAsyncRemoteLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
512 AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
513 TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
514 Toolkit::AsyncImageLoader mAsyncLocalLoader; ///< The Asynchronous image loader used to provide all local async loads
515 Toolkit::AsyncImageLoader mAsyncRemoteLoader; ///< The Asynchronous image loader used to provide all remote async loads
516 TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
523 } // namespace Toolkit
527 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_H