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] 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 * @return A TextureId to use as a handle to reference this Texture
162 TextureId RequestLoad( const VisualUrl& url,
163 TextureId maskTextureId,
164 const ImageDimensions desiredSize,
165 FittingMode::Type fittingMode,
166 Dali::SamplingMode::Type samplingMode,
167 const UseAtlas useAtlasing,
168 TextureUploadObserver* observer );
171 * Requests a masking image to be loaded. This mask is not uploaded to GL,
172 * instead, it is stored in CPU memory, and can be used for CPU blending.
174 TextureId RequestMaskLoad( const VisualUrl& maskUrl );
177 * @brief Remove a Texture from the TextureManager.
179 * Textures are cached and therefore only the removal of the last
180 * occurrence of a Texture will cause its removal internally.
182 * @param[in] textureId The ID of the Texture to remove.
184 void Remove( const TextureManager::TextureId textureId );
187 * Get the visualUrl associated with the texture id
189 const VisualUrl& GetVisualUrl( TextureId textureId );
192 * @brief Get the current state of a texture
193 * @param[in] textureId The texture id to query
194 * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
197 LoadState GetTextureState( TextureId textureId );
200 * @brief Get the associated texture set if the texture id is valid
201 * @param[in] textureId The texture Id to look up
202 * @return the associated texture set, or an empty handle if textureId is not valid
204 TextureSet GetTextureSet( TextureId textureId );
209 * @brief Requests an image load of the given URL, when the texture has
210 * have loaded, if there is a valid maskTextureId, it will perform a
211 * CPU blend with the mask, and upload the blend texture.
213 * The parameters are used to specify how the image is loaded.
214 * The observer has the UploadComplete method called when the load is ready.
216 * When the client has finished with the Texture, Remove() should be called.
218 * @param[in] url The URL of the image to load
219 * @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
220 * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
221 * @param[in] fittingMode The FittingMode to use
222 * @param[in] samplingMode The SamplingMode to use
223 * @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
224 * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
225 * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
226 * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
227 * This is called when an image load completes (or fails).
228 * @return A TextureId to use as a handle to reference this Texture
230 TextureId RequestLoadInternal(
231 const VisualUrl& url,
232 TextureId maskTextureId,
233 const ImageDimensions desiredSize,
234 FittingMode::Type fittingMode,
235 Dali::SamplingMode::Type samplingMode,
237 StorageType storageType,
238 TextureUploadObserver* observer );
241 typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
244 * @brief This struct is used to manage the life-cycle of Texture loading and caching.
248 TextureInfo( TextureId textureId,
249 TextureId maskTextureId,
250 const VisualUrl& url,
251 ImageDimensions desiredSize,
252 FittingMode::Type fittingMode,
253 Dali::SamplingMode::Type samplingMode,
254 bool loadSynchronously,
256 TextureManager::TextureHash hash )
258 desiredSize( desiredSize ),
259 useSize( desiredSize ),
260 atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
261 textureId( textureId ),
262 maskTextureId( maskTextureId ),
264 referenceCount( 1u ),
265 loadState( NOT_STARTED ),
266 fittingMode( fittingMode ),
267 samplingMode( samplingMode ),
268 storageType( UPLOAD_TO_TEXTURE ),
269 loadSynchronously( loadSynchronously ),
275 * Container type used to store all observer clients of this Texture
277 typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
279 ObserverListType observerList; ///< Container used to store all observer clients of this Texture
280 Toolkit::ImageAtlas atlas; ///< The atlas this Texture lays within (if any)
281 Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
282 TextureSet textureSet; ///< The TextureSet holding the Texture
283 VisualUrl url; ///< The URL of the image
284 ImageDimensions desiredSize; ///< The size requested
285 ImageDimensions useSize; ///< The size used
286 Vector4 atlasRect; ///< The atlas rect used if atlased
287 TextureId textureId; ///< The TextureId associated with this Texture
288 TextureId maskTextureId; ///< The mask TextureId to be applied on load
289 TextureManager::TextureHash hash; ///< The hash used to cache this Texture
290 int16_t referenceCount; ///< The reference count of clients using this Texture
291 LoadState loadState:3; ///< The load state showing the load progress of the Texture
292 FittingMode::Type fittingMode:2; ///< The requested FittingMode
293 Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
294 StorageType storageType:1; ///< CPU storage / GPU upload;
295 bool loadSynchronously:1; ///< True if synchronous loading was requested
296 UseAtlas useAtlas:1; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
302 * Struct to hold information about a requested Async load.
303 * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
305 struct AsyncLoadingInfo
307 AsyncLoadingInfo( TextureId textureId )
308 : textureId( textureId ),
313 TextureId textureId; ///< The external Texture Id assigned to this load
314 unsigned short loadId; ///< The load Id used by the async loader to reference this load
318 * @brief This struct is used within a container to manage atlas creation and destruction.
322 AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
324 textureSet( textureSet )
328 Toolkit::ImageAtlas atlas; ///< The ImageAtlas object
329 TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
334 typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
335 typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
336 typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
339 * @brief Used internally to initiate a load.
340 * @param[in] textureInfo The TextureInfo struct associated with the Texture
341 * @return True if the load was initiated
343 bool LoadTexture( TextureInfo& textureInfo );
346 * Add the observer to the observer list
347 * @param[in] textureInfo The TextureInfo struct associated with the texture
348 * observer The observer wishing to observe the texture upload
350 void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
353 * @brief This signal handler is called when the async local loader finishes loading.
354 * @param[in] id This is the async image loaders Id
355 * @param[in] pixelBuffer The loaded image data
357 void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
360 * @brief This signal handler is called when the async local loader finishes loading.
361 * @param[in] id This is the async image loaders Id
362 * @param[in] pixelBuffer The loaded image data
364 void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
367 * Common method to handle loading completion
368 * @param[in] container The Async loading container
369 * @param[in] id This is the async image loaders Id
370 * @param[in] pixelBuffer The loaded image data
372 void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
375 * @brief Performs Post-Load steps including atlasing.
376 * @param[in] textureInfo The struct associated with this Texture
377 * @param[in] pixelBuffer The image pixelBuffer
378 * @return True if successful
380 void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
383 * Check if there is a texture waiting to be masked. If there
384 * is then apply this mask and upload it.
385 * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
387 void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
390 * Apply the mask to the pixelBuffer.
391 * @param[in] pixelBuffer The pixelBuffer to apply the mask to
392 * @param[in] maskTextureId The texture id of the mask.
394 void ApplyMask( Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId );
397 * Upload the texture specified in pixelBuffer to the appropriate location
398 * @param[in] pixelBuffer The image data to upload
399 * @param[in] textureInfo The texture info containing the location to
402 void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
405 * Mark the texture as complete, and inform observers
406 * @param[in] textureInfo The struct associated with this Texture
408 void UploadComplete( TextureInfo& textureInfo );
411 * Notify the current observers that the texture upload is complete,
412 * then remove the observers from the list.
413 * @param[in] textureInfo The struct associated with this Texture
414 * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
416 void NotifyObservers( TextureInfo& textureInfo, bool success );
419 * @brief Generates a new, unique TextureId
420 * @return A unique TextureId
422 TextureManager::TextureId GenerateUniqueTextureId();
425 * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
426 * @param[in] textureId The TextureId to look up
427 * @return The cache index
429 int GetCacheIndexFromId( TextureId textureId );
433 * @brief Generates a hash for caching based on the input parameters.
434 * Only applies size, fitting mode andsampling mode if the size is specified.
435 * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
436 * Always applies useAtlas.
437 * @param[in] url The URL of the image to load
438 * @param[in] size The image size
439 * @param[in] fittingMode The FittingMode to use
440 * @param[in] samplingMode The SamplingMode to use
441 * @param[in] useAtlas True if atlased
442 * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
443 * @return A hash of the provided data for caching.
445 TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
446 const FittingMode::Type fittingMode,
447 const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
448 TextureId maskTextureId );
451 * @brief Looks up a cached texture by its hash.
452 * If found, the given parameters are used to check there is no hash-collision.
453 * @param[in] hash The hash to look up
454 * @param[in] url The URL of the image to load
455 * @param[in] size The image size
456 * @param[in] fittingMode The FittingMode to use
457 * @param[in] samplingMode The SamplingMode to use
458 * @param[in] useAtlas True if atlased
459 * @param[in] maskTextureId Optional texture ID to use to mask this image
460 * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
462 TextureManager::TextureId FindCachedTexture(
463 const TextureManager::TextureHash hash,
464 const std::string& url,
465 const ImageDimensions size,
466 const FittingMode::Type fittingMode,
467 const Dali::SamplingMode::Type samplingMode,
469 TextureId maskTextureId );
475 * Undefined copy constructor.
477 TextureManager( const TextureManager& );
480 * Undefined assignment operator.
482 TextureManager& operator=( const TextureManager& rhs );
485 * This is called by the TextureManagerUploadObserver when an observer is destroyed.
486 * We use the callback to know when to remove an observer from our notify list.
487 * @param[in] observer The observer that generated the callback
489 void ObserverDestroyed( TextureUploadObserver* observer );
491 private: // Member Variables:
493 AsyncLoadingInfoContainerType mAsyncLocalLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
494 AsyncLoadingInfoContainerType mAsyncRemoteLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
495 AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
496 TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
497 Toolkit::AsyncImageLoader mAsyncLocalLoader; ///< The Asynchronous image loader used to provide all local async loads
498 Toolkit::AsyncImageLoader mAsyncRemoteLoader; ///< The Asynchronous image loader used to provide all remote async loads
499 TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
506 } // namespace Toolkit
510 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_H