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>
29 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
30 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
31 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
32 #include <dali-toolkit/internal/visuals/visual-url.h>
44 class MaskTextureObserver;
47 * The TextureManager provides a common Image loading API for Visuals.
49 * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
50 * Texture caching is provided and performed when possible.
51 * Broken Images are automatically provided on load failure.
53 class TextureManager : public ConnectionTracker
57 typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
58 static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
61 * Whether the texture should be atlased or uploaded into it's own GPU texture
70 * Whether the texture should be stored in CPU memory, or uploaded to a GPU texture
79 * Whether the texture should be loaded synchronously or asynchronously.
88 * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
92 NOT_STARTED, ///< Default
93 LOADING, ///< Loading has been started, but not finished.
94 LOAD_FINISHED, ///< Loading has finished. (for CPU storage only)
95 WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
96 UPLOADED, ///< Uploaded and ready. (For GPU upload only)
97 CANCELLED, ///< Removed before loading completed
98 LOAD_FAILED ///< Async loading failed, e.g. connection problem
114 // TextureManager Main API:
117 * @brief Requests an image load of the given URL.
119 * The parameters are used to specify how the image is loaded.
120 * The observer has the UploadComplete method called when the load is ready.
122 * When the client has finished with the Texture, Remove() should be called.
124 * @param[in] url The URL of the image to load
125 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
126 * @param[in] fittingMode The FittingMode to use
127 * @param[in] samplingMode The SamplingMode to use
128 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
129 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
130 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
131 * This is called when an image load completes (or fails).
132 * @return A TextureId to use as a handle to reference this Texture
134 TextureId RequestLoad( const VisualUrl& url,
135 const ImageDimensions desiredSize,
136 FittingMode::Type fittingMode,
137 Dali::SamplingMode::Type samplingMode,
138 const UseAtlas useAtlasing,
139 TextureUploadObserver* observer );
142 * @brief Requests an image load of the given URL, when the texture has
143 * have loaded, it will perform a CPU blend with the image mask, and upload
146 * The parameters are used to specify how the image is loaded.
147 * The observer has the UploadComplete method called when the load is ready.
149 * When the client has finished with the Texture, Remove() should be called.
151 * @param[in] url The URL of the image to load
152 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
153 * @param[in] fittingMode The FittingMode to use
154 * @param[in] samplingMode The SamplingMode to use
155 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
156 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
157 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
158 * This is called when an image load completes (or fails).
159 * @return A TextureId to use as a handle to reference this Texture
161 TextureId RequestLoad( const VisualUrl& url,
162 TextureId maskTextureId,
163 const ImageDimensions desiredSize,
164 FittingMode::Type fittingMode,
165 Dali::SamplingMode::Type samplingMode,
166 const UseAtlas useAtlasing,
167 TextureUploadObserver* observer );
170 * Requests a masking image to be loaded. This mask is not uploaded to GL,
171 * instead, it is stored in CPU memory, and can be used for CPU blending.
173 TextureId RequestMaskLoad( const VisualUrl& maskUrl );
176 * @brief Remove a Texture from the TextureManager.
178 * Textures are cached and therefore only the removal of the last
179 * occurrence of a Texture will cause its removal internally.
181 * @param[in] textureId The ID of the Texture to remove.
183 void Remove( const TextureManager::TextureId textureId );
186 * @brief Get the current state of a texture
187 * @param[in] textureId The texture id to query
188 * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
191 LoadState GetTextureState( TextureId textureId );
194 * @brief Get the associated texture set if the texture id is valid
195 * @param[in] textureId The texture Id to look up
196 * @return the associated texture set, or an empty handle if textureId is not valid
198 TextureSet GetTextureSet( TextureId textureId );
203 * @brief Requests an image load of the given URL, when the texture has
204 * have loaded, if there is a valid maskTextureId, it will perform a
205 * CPU blend with the mask, and upload the blend texture.
207 * The parameters are used to specify how the image is loaded.
208 * The observer has the UploadComplete method called when the load is ready.
210 * When the client has finished with the Texture, Remove() should be called.
212 * @param[in] url The URL of the image to load
213 * @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
214 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
215 * @param[in] fittingMode The FittingMode to use
216 * @param[in] samplingMode The SamplingMode to use
217 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
218 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
219 * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
220 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
221 * This is called when an image load completes (or fails).
222 * @return A TextureId to use as a handle to reference this Texture
224 TextureId RequestInternalLoad(
225 const VisualUrl& url,
226 TextureId maskTextureId,
227 const ImageDimensions desiredSize,
228 FittingMode::Type fittingMode,
229 Dali::SamplingMode::Type samplingMode,
231 StorageType storageType,
232 TextureUploadObserver* observer );
235 typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
238 * @brief This struct is used to manage the life-cycle of Texture loading and caching.
242 TextureInfo( TextureId textureId,
243 TextureId maskTextureId,
244 const VisualUrl& url,
245 ImageDimensions desiredSize,
246 FittingMode::Type fittingMode,
247 Dali::SamplingMode::Type samplingMode,
248 bool loadSynchronously,
250 TextureManager::TextureHash hash )
252 desiredSize( desiredSize ),
253 useSize( desiredSize ),
254 atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
255 textureId( textureId ),
256 maskTextureId( maskTextureId ),
258 referenceCount( 1u ),
259 loadState( NOT_STARTED ),
260 fittingMode( fittingMode ),
261 samplingMode( samplingMode ),
262 storageType( GPU_UPLOAD ),
263 loadSynchronously( loadSynchronously ),
269 * Container type used to store all observer clients of this Texture
271 typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
273 ObserverListType observerList; ///< Container used to store all observer clients of this Texture
274 Toolkit::ImageAtlas atlas; ///< The atlas this Texture lays within (if any)
275 PixelData pixelData; ///< The PixelData holding the image data (this is used if atlasing is deferred or CPU storage is required)
276 TextureSet textureSet; ///< The TextureSet holding the Texture
277 VisualUrl url; ///< The URL of the image
278 ImageDimensions desiredSize; ///< The size requested
279 ImageDimensions useSize; ///< The size used
280 Vector4 atlasRect; ///< The atlas rect used if atlased
281 TextureId textureId; ///< The TextureId associated with this Texture
282 TextureId maskTextureId; ///< The mask TextureId to be applied on load
283 TextureManager::TextureHash hash; ///< The hash used to cache this Texture
284 int16_t referenceCount; ///< The reference count of clients using this Texture
285 LoadState loadState:3; ///< The load state showing the load progress of the Texture
286 FittingMode::Type fittingMode:2; ///< The requested FittingMode
287 Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
288 StorageType storageType:1; ///< CPU storage / GPU upload;
289 bool loadSynchronously:1; ///< True if synchronous loading was requested
290 UseAtlas useAtlas:1; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
296 * Struct to hold information about a requested Async load.
297 * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
299 struct AsyncLoadingInfo
301 AsyncLoadingInfo( TextureId textureId )
302 : textureId( textureId ),
307 TextureId textureId; ///< The external Texture Id assigned to this load
308 unsigned short loadId; ///< The load Id used by the async loader to reference this load
312 * @brief This struct is used within a container to manage atlas creation and destruction.
316 AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
318 textureSet( textureSet )
322 Toolkit::ImageAtlas atlas; ///< The ImageAtlas object
323 TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
328 typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
329 typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
330 typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
333 * @brief Used internally to initiate a load.
334 * @param[in] textureInfo The TextureInfo struct associated with the Texture
335 * @return True if the load was initiated
337 bool LoadTexture( TextureInfo& textureInfo );
340 * Add the observer to the observer list
341 * @param[in] textureInfo The TextureInfo struct associated with the texture
342 * observer The observer wishing to observe the texture upload
344 void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
347 * @brief This signal handler is called when the async local loader finishes loading.
348 * @param[in] id This is the async image loaders Id
349 * @param[in] pixelData The loaded image data
351 void AsyncLocalLoadComplete( uint32_t id, PixelData pixelData );
354 * @brief This signal handler is called when the async local loader finishes loading.
355 * @param[in] id This is the async image loaders Id
356 * @param[in] pixelData The loaded image data
358 void AsyncRemoteLoadComplete( uint32_t id, PixelData pixelData );
361 * Common method to handle loading completion
362 * @param[in] container The Async loading container
363 * @param[in] id This is the async image loaders Id
364 * @param[in] pixelData The loaded image data
366 void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, PixelData pixelData );
369 * @brief Performs Post-Load steps including atlasing.
370 * @param[in] textureInfo The struct associated with this Texture
371 * @param[in] pixelData The image pixelData
372 * @return True if successful
374 void PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
377 * Check if there is a texture waiting to be masked. If there
378 * is then apply this mask and upload it.
379 * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
381 void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
384 * Apply the mask texture to the image texture.
385 * @param[in] pixelData The image pixelData to apply the mask to
386 * @param[in] maskTextureId The texture id of the mask.
388 void ApplyMask( PixelData pixelData, TextureId maskTextureId );
391 * Upload the texture specified in pixelData to the appropriate location
392 * @param[in] pixelData The image data to upload
393 * @param[in] textureInfo The texture info containing the location to
396 void UploadTexture( PixelData pixelData, TextureInfo& textureInfo );
399 * Mark the texture as complete, and inform observers
400 * @param[in] textureInfo The struct associated with this Texture
402 void UploadComplete( TextureInfo& textureInfo );
405 * Notify the current observers that the texture upload is complete,
406 * then remove the observers from the list.
407 * @param[in] textureInfo The struct associated with this Texture
408 * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
410 void NotifyObservers( TextureInfo& textureInfo, bool success );
413 * @brief Generates a new, unique TextureId
414 * @return A unique TextureId
416 TextureManager::TextureId GenerateUniqueTextureId();
419 * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
420 * @param[in] textureId The TextureId to look up
421 * @return The cache index
423 int GetCacheIndexFromId( TextureId textureId );
427 * @brief Generates a hash for caching based on the input parameters.
428 * Only applies size, fitting mode andsampling mode if the size is specified.
429 * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
430 * Always applies useAtlas.
431 * @param[in] url The URL of the image to load
432 * @param[in] size The image size
433 * @param[in] fittingMode The FittingMode to use
434 * @param[in] samplingMode The SamplingMode to use
435 * @param[in] useAtlas True if atlased
436 * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
437 * @return A hash of the provided data for caching.
439 TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
440 const FittingMode::Type fittingMode,
441 const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
442 TextureId maskTextureId );
445 * @brief Looks up a cached texture by its hash.
446 * If found, the given parameters are used to check there is no hash-collision.
447 * @param[in] hash The hash to look up
448 * @param[in] url The URL of the image to load
449 * @param[in] size The image size
450 * @param[in] fittingMode The FittingMode to use
451 * @param[in] samplingMode The SamplingMode to use
452 * @param[in] useAtlas True if atlased
453 * @param[in] maskTextureId Optional texture ID to use to mask this image
454 * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
456 TextureManager::TextureId FindCachedTexture(
457 const TextureManager::TextureHash hash,
458 const std::string& url,
459 const ImageDimensions size,
460 const FittingMode::Type fittingMode,
461 const Dali::SamplingMode::Type samplingMode,
463 TextureId maskTextureId );
469 * Undefined copy constructor.
471 TextureManager( const TextureManager& );
474 * Undefined assignment operator.
476 TextureManager& operator=( const TextureManager& rhs );
479 * This is called by the TextureManagerUploadObserver when an observer is destroyed.
480 * We use the callback to know when to remove an observer from our notify list.
481 * @param[in] observer The observer that generated the callback
483 void ObserverDestroyed( TextureUploadObserver* observer );
485 private: // Member Variables:
487 AsyncLoadingInfoContainerType mAsyncLocalLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
488 AsyncLoadingInfoContainerType mAsyncRemoteLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
489 AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
490 TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
491 Toolkit::AsyncImageLoader mAsyncLocalLoader; ///< The Asynchronous image loader used to provide all local async loads
492 Toolkit::AsyncImageLoader mAsyncRemoteLoader; ///< The Asynchronous image loader used to provide all remote async loads
493 TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
500 } // namespace Toolkit
504 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_H