Merge "Support FastTrackUploading for YUV images" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/image/image-visual.h>
20
21 // EXTERNAL HEADERS
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/devel-api/rendering/texture-devel.h>
26 #include <dali/devel-api/scripting/enum-helper.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/actors/layer.h>
30 #include <dali/public-api/adaptor-framework/async-task-manager.h>
31 #include <dali/public-api/rendering/decorated-visual-renderer.h>
32 #include <cstring> // for strlen()
33
34 // INTERNAL HEADERS
35 #include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
36 #include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
37 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
38 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
39 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
40 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
41 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
42 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
43 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
44 #include <dali-toolkit/internal/visuals/visual-url.h>
45 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
46 #include <dali-toolkit/public-api/visuals/visual-properties.h>
47
48 namespace Dali
49 {
50 namespace Toolkit
51 {
52 namespace Internal
53 {
54 namespace
55 {
56 const int CUSTOM_PROPERTY_COUNT(7); // ltr, wrap, pixel area, atlas, pixalign, crop to mask, mask texture ratio
57
58 // fitting modes
59 DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
61   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL)
62   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH)
63   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT)
64   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT)
65 DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE)
66
67 // sampling modes
68 DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE)
69   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX)
70   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST)
71   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR)
72   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST)
73   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR)
74   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER)
75   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE)
76 DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE)
77
78 // wrap modes
79 DALI_ENUM_TO_STRING_TABLE_BEGIN(WRAP_MODE)
80   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, DEFAULT)
81   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, CLAMP_TO_EDGE)
82   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, REPEAT)
83   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT)
84 DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE)
85
86 // load policies
87 DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY)
88   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE)
89   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED)
90 DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY)
91
92 // release policies
93 DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY)
94   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED)
95   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED)
96   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER)
97 DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY)
98
99 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
100
101 constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u;
102
103 Geometry CreateGeometry(VisualFactoryCache& factoryCache, ImageDimensions gridSize)
104 {
105   Geometry geometry;
106
107   if(gridSize == ImageDimensions(1, 1))
108   {
109     geometry = factoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
110   }
111   else
112   {
113     geometry = VisualFactoryCache::CreateGridGeometry(gridSize);
114   }
115
116   return geometry;
117 }
118
119 } // unnamed namespace
120
121 ImageVisualPtr ImageVisual::New(VisualFactoryCache&       factoryCache,
122                                 ImageVisualShaderFactory& shaderFactory,
123                                 const VisualUrl&          imageUrl,
124                                 const Property::Map&      properties,
125                                 ImageDimensions           size,
126                                 FittingMode::Type         fittingMode,
127                                 Dali::SamplingMode::Type  samplingMode)
128 {
129   ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode));
130   imageVisualPtr->SetProperties(properties);
131   imageVisualPtr->Initialize();
132   return imageVisualPtr;
133 }
134
135 ImageVisualPtr ImageVisual::New(VisualFactoryCache&       factoryCache,
136                                 ImageVisualShaderFactory& shaderFactory,
137                                 const VisualUrl&          imageUrl,
138                                 ImageDimensions           size,
139                                 FittingMode::Type         fittingMode,
140                                 Dali::SamplingMode::Type  samplingMode)
141 {
142   ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode));
143   imageVisualPtr->Initialize();
144   return imageVisualPtr;
145 }
146
147 ImageVisual::ImageVisual(VisualFactoryCache&       factoryCache,
148                          ImageVisualShaderFactory& shaderFactory,
149                          const VisualUrl&          imageUrl,
150                          ImageDimensions           size,
151                          FittingMode::Type         fittingMode,
152                          Dali::SamplingMode::Type  samplingMode)
153 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::IMAGE),
154   mPixelArea(FULL_TEXTURE_RECT),
155   mPlacementActor(),
156   mImageUrl(imageUrl),
157   mMaskingData(),
158   mDesiredSize(size),
159   mTextureId(TextureManager::INVALID_TEXTURE_ID),
160   mTextures(),
161   mImageVisualShaderFactory(shaderFactory),
162   mFittingMode(fittingMode),
163   mSamplingMode(samplingMode),
164   mWrapModeU(WrapMode::DEFAULT),
165   mWrapModeV(WrapMode::DEFAULT),
166   mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
167   mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
168   mAtlasRect(0.0f, 0.0f, 0.0f, 0.0f),
169   mAtlasRectSize(0, 0),
170   mLoadState(TextureManager::LoadState::NOT_STARTED),
171   mAttemptAtlasing(false),
172   mOrientationCorrection(true),
173   mEnableBrokenImage(true)
174 {
175   EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad());
176 }
177
178 ImageVisual::~ImageVisual()
179 {
180   if(Stage::IsInstalled())
181   {
182     if(mImageUrl.IsValid())
183     {
184       // Decrease reference count of External Resources :
185       // EncodedImageBuffer or ExternalTextures.
186       // Ensure the stage is still valid before accessing texture manager.
187       if(mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
188       {
189         TextureManager& textureManager = mFactoryCache.GetTextureManager();
190         textureManager.RemoveExternalTexture(mImageUrl.GetUrl());
191       }
192       else if(mImageUrl.IsBufferResource())
193       {
194         TextureManager& textureManager = mFactoryCache.GetTextureManager();
195         textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
196       }
197     }
198
199     // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
200     if((mTextureId != TextureManager::INVALID_TEXTURE_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER))
201     {
202       RemoveTexture();
203     }
204
205     ResetFastTrackLoadingTask();
206   }
207 }
208
209 void ImageVisual::DoSetProperties(const Property::Map& propertyMap)
210 {
211   // Url is already received in constructor
212   for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
213   {
214     KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
215     if(keyValue.first.type == Property::Key::INDEX)
216     {
217       DoSetProperty(keyValue.first.indexKey, keyValue.second);
218     }
219     else
220     {
221       if(keyValue.first == IMAGE_FITTING_MODE)
222       {
223         DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second);
224       }
225       else if(keyValue.first == IMAGE_SAMPLING_MODE)
226       {
227         DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second);
228       }
229       else if(keyValue.first == IMAGE_DESIRED_WIDTH)
230       {
231         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
232       }
233       else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
234       {
235         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
236       }
237       else if(keyValue.first == PIXEL_AREA_UNIFORM_NAME)
238       {
239         DoSetProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second);
240       }
241       else if(keyValue.first == IMAGE_WRAP_MODE_U)
242       {
243         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second);
244       }
245       else if(keyValue.first == IMAGE_WRAP_MODE_V)
246       {
247         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second);
248       }
249       else if(keyValue.first == SYNCHRONOUS_LOADING)
250       {
251         DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
252       }
253       else if(keyValue.first == IMAGE_ATLASING)
254       {
255         DoSetProperty(Toolkit::ImageVisual::Property::ATLASING, keyValue.second);
256       }
257       else if(keyValue.first == ALPHA_MASK_URL)
258       {
259         DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second);
260       }
261       else if(keyValue.first == MASK_CONTENT_SCALE_NAME)
262       {
263         DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second);
264       }
265       else if(keyValue.first == CROP_TO_MASK_NAME)
266       {
267         DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second);
268       }
269       else if(keyValue.first == MASKING_TYPE_NAME)
270       {
271         DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, keyValue.second);
272       }
273       else if(keyValue.first == ENABLE_BROKEN_IMAGE)
274       {
275         DoSetProperty(Toolkit::DevelImageVisual::Property::ENABLE_BROKEN_IMAGE, keyValue.second);
276       }
277       else if(keyValue.first == LOAD_POLICY_NAME)
278       {
279         DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
280       }
281       else if(keyValue.first == RELEASE_POLICY_NAME)
282       {
283         DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second);
284       }
285       else if(keyValue.first == ORIENTATION_CORRECTION_NAME)
286       {
287         DoSetProperty(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second);
288       }
289       else if(keyValue.first == FAST_TRACK_UPLOADING_NAME)
290       {
291         DoSetProperty(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, keyValue.second);
292       }
293     }
294   }
295   // Load image immediately if LOAD_POLICY requires it
296   if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE)
297   {
298     auto attemptAtlasing = AttemptAtlasing();
299     LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED);
300   }
301 }
302
303 void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& value)
304 {
305   switch(index)
306   {
307     case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
308     {
309       bool sync = false;
310       if(value.Get(sync))
311       {
312         if(sync)
313         {
314           mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
315         }
316         else
317         {
318           mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
319         }
320       }
321       else
322       {
323         DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
324       }
325       break;
326     }
327
328     case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
329     {
330       int32_t desiredWidth = 0;
331       if(value.Get(desiredWidth))
332       {
333         mDesiredSize.SetWidth(desiredWidth);
334       }
335       else
336       {
337         DALI_LOG_ERROR("ImageVisual: desiredWidth property has incorrect type\n");
338       }
339       break;
340     }
341
342     case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
343     {
344       int32_t desiredHeight = 0;
345       if(value.Get(desiredHeight))
346       {
347         mDesiredSize.SetHeight(desiredHeight);
348       }
349       else
350       {
351         DALI_LOG_ERROR("ImageVisual: desiredHeight property has incorrect type\n");
352       }
353       break;
354     }
355
356     case Toolkit::ImageVisual::Property::FITTING_MODE:
357     {
358       int fittingMode = 0;
359       Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode);
360       mFittingMode = Dali::FittingMode::Type(fittingMode);
361       break;
362     }
363
364     case Toolkit::ImageVisual::Property::SAMPLING_MODE:
365     {
366       int samplingMode = 0;
367       Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode);
368       mSamplingMode = Dali::SamplingMode::Type(samplingMode);
369       break;
370     }
371
372     case Toolkit::ImageVisual::Property::PIXEL_AREA:
373     {
374       value.Get(mPixelArea);
375       break;
376     }
377
378     case Toolkit::ImageVisual::Property::WRAP_MODE_U:
379     {
380       int wrapMode = 0;
381       Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode);
382       mWrapModeU = Dali::WrapMode::Type(wrapMode);
383       break;
384     }
385
386     case Toolkit::ImageVisual::Property::WRAP_MODE_V:
387     {
388       int wrapMode = 0;
389       Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode);
390       mWrapModeV = Dali::WrapMode::Type(wrapMode);
391       break;
392     }
393
394     case Toolkit::ImageVisual::Property::ATLASING:
395     {
396       value.Get(mAttemptAtlasing);
397       break;
398     }
399
400     case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
401     {
402       std::string alphaUrl = "";
403       if(value.Get(alphaUrl))
404       {
405         AllocateMaskData();
406         mMaskingData->mAlphaMaskUrl = alphaUrl;
407       }
408       break;
409     }
410
411     case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
412     {
413       float scale = 1.0f;
414       if(value.Get(scale))
415       {
416         AllocateMaskData();
417         mMaskingData->mContentScaleFactor = scale;
418       }
419       break;
420     }
421
422     case Toolkit::ImageVisual::Property::CROP_TO_MASK:
423     {
424       bool crop = false;
425       if(value.Get(crop))
426       {
427         AllocateMaskData();
428         mMaskingData->mCropToMask = crop;
429       }
430       break;
431     }
432
433     case Toolkit::DevelImageVisual::Property::MASKING_TYPE:
434     {
435       int maskingType = 0;
436       if(value.Get(maskingType))
437       {
438         AllocateMaskData();
439         if(mImageUrl.IsValid() && mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
440         {
441           // For external textures, only gpu masking is available.
442           // Therefore, MASKING_TYPE is set to MASKING_ON_RENDERING forcelly.
443           mMaskingData->mPreappliedMasking = false;
444         }
445         else
446         {
447           mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false;
448         }
449       }
450       break;
451     }
452
453     case Toolkit::DevelImageVisual::Property::ENABLE_BROKEN_IMAGE:
454     {
455       bool enableBrokenImage(mEnableBrokenImage);
456       if(value.Get(enableBrokenImage))
457       {
458         mEnableBrokenImage = enableBrokenImage;
459       }
460       break;
461     }
462
463     case Toolkit::ImageVisual::Property::RELEASE_POLICY:
464     {
465       int releasePolicy = 0;
466       Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy);
467       mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy);
468       break;
469     }
470
471     case Toolkit::ImageVisual::Property::LOAD_POLICY:
472     {
473       int loadPolicy = 0;
474       Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy);
475       mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
476       break;
477     }
478     case Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION:
479     {
480       bool orientationCorrection(mOrientationCorrection);
481       if(value.Get(orientationCorrection))
482       {
483         mOrientationCorrection = orientationCorrection;
484       }
485       break;
486     }
487
488     case Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING:
489     {
490       bool fastTrackUploading = false;
491       if(value.Get(fastTrackUploading))
492       {
493         mUseFastTrackUploading = fastTrackUploading;
494       }
495       break;
496     }
497   }
498 }
499
500 void ImageVisual::AllocateMaskData()
501 {
502   if(!mMaskingData)
503   {
504     mMaskingData.reset(new TextureManager::MaskingData());
505     if(mImageUrl.IsValid() && mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
506     {
507       mMaskingData->mPreappliedMasking = false;
508     }
509   }
510 }
511
512 void ImageVisual::GetNaturalSize(Vector2& naturalSize)
513 {
514   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
515   {
516     naturalSize.x = mDesiredSize.GetWidth();
517     naturalSize.y = mDesiredSize.GetHeight();
518     return;
519   }
520   else if(mImpl->mRenderer) // Check if we have a loaded image
521   {
522     if(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED)
523     {
524       naturalSize.x = mAtlasRectSize.GetWidth();
525       naturalSize.y = mAtlasRectSize.GetHeight();
526       return;
527     }
528
529     auto textureSet = mImpl->mRenderer.GetTextures();
530     if(textureSet && textureSet.GetTextureCount())
531     {
532       if(mTextureSize != Vector2::ZERO)
533       {
534         naturalSize = mTextureSize;
535         return;
536       }
537     }
538   }
539
540   if(mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() &&
541      mMaskingData->mCropToMask)
542   {
543     ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl());
544     if(dimensions != ImageDimensions(0, 0))
545     {
546       naturalSize.x = dimensions.GetWidth();
547       naturalSize.y = dimensions.GetHeight();
548     }
549     return;
550   }
551   else if(mImageUrl.IsValid())
552   {
553     if(mImageUrl.GetProtocolType() == VisualUrl::LOCAL)
554     {
555       ImageDimensions dimensions = Dali::GetClosestImageSize(mImageUrl.GetUrl());
556
557       if(dimensions != ImageDimensions(0, 0))
558       {
559         naturalSize.x = dimensions.GetWidth();
560         naturalSize.y = dimensions.GetHeight();
561       }
562       else
563       {
564         Actor   actor     = mPlacementActor.GetHandle();
565         Vector2 imageSize = Vector2::ZERO;
566         if(actor)
567         {
568           imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
569         }
570         else
571         {
572           imageSize = mPlacementActorSize;
573         }
574
575         mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
576         Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0);
577         naturalSize.x       = brokenImage.GetWidth();
578         naturalSize.y       = brokenImage.GetWidth();
579       }
580       return;
581     }
582   }
583   naturalSize = Vector2::ZERO;
584 }
585
586 void ImageVisual::OnInitialize()
587 {
588   Geometry geometry;
589
590   // Get the geometry
591   if(mImpl->mCustomShader)
592   {
593     geometry = CreateGeometry(mFactoryCache, mImpl->mCustomShader->mGridSize);
594   }
595   else // Get any geometry associated with the texture
596   {
597     TextureManager& textureManager = mFactoryCache.GetTextureManager();
598
599     uint32_t firstElementCount{0u};
600     uint32_t secondElementCount{0u};
601     geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
602
603     if(!firstElementCount && !secondElementCount) // Otherwise use quad
604     {
605       geometry = CreateGeometry(mFactoryCache, ImageDimensions(1, 1));
606     }
607   }
608
609   // Increase reference count of External Resources :
610   // EncodedImageBuffer or ExternalTextures.
611   // Reference count will be decreased at destructor of the visual.
612   if(mImageUrl.IsValid() && (mImageUrl.IsBufferResource() || mImageUrl.GetProtocolType() == VisualUrl::TEXTURE))
613   {
614     TextureManager& textureManager = mFactoryCache.GetTextureManager();
615     textureManager.UseExternalResource(mImageUrl.GetUrl());
616   }
617
618   Shader shader = GenerateShader();
619
620   // Create the renderer
621   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
622   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
623
624   //Register transform properties
625   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
626
627   EnablePreMultipliedAlpha(IsPreMultipliedAlphaEnabled());
628
629   if(mMaskingData)
630   {
631     mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
632   }
633 }
634
635 void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, TextureManager::ReloadPolicy forceReload)
636 {
637   TextureManager& textureManager = mFactoryCache.GetTextureManager();
638
639   ImageAtlasManagerPtr atlasManager        = nullptr;
640   AtlasUploadObserver* atlasUploadObserver = nullptr;
641   auto                 textureObserver     = this;
642
643   if(atlasing)
644   {
645     atlasManager        = mFactoryCache.GetAtlasManager();
646     atlasUploadObserver = this;
647   }
648
649   auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
650                              ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
651                              : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
652
653   bool synchronousLoading = IsSynchronousLoadingRequired();
654   bool loadingStatus      = false;
655
656   // Remove previous loading task.
657   ResetFastTrackLoadingTask();
658
659   // Rare case. If someone call LoadTexture during fast track loading task running, (Ex : Action::RELOAD)
660   // we should remove previously added renderer now.
661   if(mRendererAdded)
662   {
663     Actor actor = mPlacementActor.GetHandle();
664     if(actor)
665     {
666       actor.RemoveRenderer(mImpl->mRenderer);
667       mRendererAdded = false;
668     }
669   }
670
671   /**
672    * @brief Check whether FastTrackUploading is avaliable or not.
673    * @return True if we can use fast track uploading feature. False otherwise.
674    */
675   auto IsFastTrackUploadingAvailable = [&]() {
676     if(mUseFastTrackUploading &&
677        mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::ATTACHED &&
678        mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED &&
679        forceReload == TextureManager::ReloadPolicy::CACHED &&
680        (mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE) &&
681        !synchronousLoading &&
682        !atlasing &&
683        !mImpl->mCustomShader &&
684        !(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()))
685     {
686       return true;
687     }
688     else if(mUseFastTrackUploading)
689     {
690       DALI_LOG_DEBUG_INFO("FastTrack : Fail to load fast track. mUrl : [%s]%s%s%s%s%s%s%s%s\n",
691                           mImageUrl.GetUrl().c_str(),
692                           (mLoadPolicy != Toolkit::ImageVisual::LoadPolicy::ATTACHED) ? "/ mLoadPolicy != ATTACHED" : "",
693                           (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::DETACHED) ? "/ mReleasePolicy != DETACHED" : "",
694                           (forceReload != TextureManager::ReloadPolicy::CACHED) ? "/ forceReload != CACHED" : "",
695                           (!(mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE)) ? "/ url is not image" : "",
696                           (synchronousLoading) ? "/ synchronousLoading" : "",
697                           (atlasing) ? "/ atlasing" : "",
698                           (mImpl->mCustomShader) ? "/ use customs shader" : "",
699                           (mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()) ? "/ use masking url" : "");
700     }
701     return false;
702   };
703
704   if(IsFastTrackUploadingAvailable())
705   {
706     // Enable PremultipliedAlpha first.
707     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
708
709     // Set new TextureSet with fast track loading task
710     mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, mFactoryCache.GetLoadYuvPlanes(), MakeCallback(this, &ImageVisual::FastLoadComplete));
711
712     TextureSet textureSet = TextureSet::New();
713     if(!mFastTrackLoadingTask->mLoadPlanesAvaliable)
714     {
715       DALI_ASSERT_ALWAYS(mFastTrackLoadingTask->mTextures.size() >= 1u);
716       textureSet.SetTexture(0u, mFastTrackLoadingTask->mTextures[0]);
717     }
718     else
719     {
720       DALI_ASSERT_ALWAYS(mFastTrackLoadingTask->mTextures.size() >= 3u);
721       textureSet.SetTexture(0u, mFastTrackLoadingTask->mTextures[0]);
722       textureSet.SetTexture(1u, mFastTrackLoadingTask->mTextures[1]);
723       textureSet.SetTexture(2u, mFastTrackLoadingTask->mTextures[2]);
724
725       // We cannot determine what kind of shader will be used.
726       // Just use unified shader, and then change shader after load completed.
727       mNeedUnifiedYuvAndRgb = true;
728       UpdateShader();
729     }
730     mImpl->mRenderer.SetTextures(textureSet);
731
732     Dali::AsyncTaskManager::Get().AddTask(mFastTrackLoadingTask);
733
734     mLoadState = TextureManager::LoadState::LOADING;
735   }
736   else
737   {
738     textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
739   }
740
741   if(textures)
742   {
743     if(loadingStatus)
744     {
745       mLoadState = TextureManager::LoadState::LOADING;
746     }
747     else
748     {
749       mLoadState = TextureManager::LoadState::LOAD_FINISHED;
750     }
751
752     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
753     if(!atlasing)
754     {
755       Sampler sampler = Sampler::New();
756       sampler.SetWrapMode(mWrapModeU, mWrapModeV);
757       textures.SetSampler(0u, sampler);
758     }
759   }
760   else if(synchronousLoading)
761   {
762     // Synchronous loading is failed
763     mLoadState = TextureManager::LoadState::LOAD_FAILED;
764   }
765
766   if(atlasing) // Flag needs to be set before creating renderer
767   {
768     mImpl->mFlags |= Visual::Base::Impl::IS_ATLASING_APPLIED;
769   }
770   else
771   {
772     mImpl->mFlags &= ~Visual::Base::Impl::IS_ATLASING_APPLIED;
773   }
774 }
775
776 bool ImageVisual::AttemptAtlasing()
777 {
778   return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing);
779 }
780
781 void ImageVisual::InitializeRenderer()
782 {
783   auto attemptAtlasing = AttemptAtlasing();
784
785   // Load Texture if mTextures is empty.
786   // mTextures is already set, the mTexture can be used to create Renderer.
787   // There are two cases mTextures is empty.
788   // 1. mTextureId == TextureManager::INVALID_TEXTURE_ID
789   //  - Visual is on stage with LoadPolicy::ATTACHED
790   // 2. mTextureId != TextureManager::INVALID_TEXTURE_ID
791   //  - If ReleasePolicy is DESTROYED, InitializeRenderer called every on stage called.
792   //  - Then every resources those contained in Visual are Reset but mTextureId is remained when the Off stage time,
793   //  - So, mTextures needed to be get from texture manager to created resources like mImpl->mRenderer.
794   if(!mTextures)
795   {
796     if(mTextureId == TextureManager::INVALID_TEXTURE_ID)
797     {
798       LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED);
799     }
800     else
801     {
802       mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId);
803       if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) && mTextures)
804       {
805         Sampler sampler = Sampler::New();
806         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
807         mTextures.SetSampler(0u, sampler);
808       }
809     }
810   }
811
812   if(mTextures)
813   {
814     mImpl->mRenderer.SetTextures(mTextures);
815     ComputeTextureSize();
816     CheckMaskTexture();
817
818     bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0));
819
820     if(mTextures.GetTextureCount() == 3)
821     {
822       if(mTextures.GetTexture(0).GetPixelFormat() == Pixel::L8 && mTextures.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && mTextures.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
823       {
824         mNeedYuvToRgb      = true;
825         needToUpdateShader = true;
826       }
827     }
828
829     if(needToUpdateShader)
830     {
831       UpdateShader();
832     }
833     mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
834   }
835
836   if(attemptAtlasing) // the texture is packed inside atlas
837   {
838     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
839
840     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
841
842     if(!defaultWrapMode) // custom wrap mode
843     {
844       Vector2 wrapMode(mWrapModeU - WrapMode::CLAMP_TO_EDGE, mWrapModeV - WrapMode::CLAMP_TO_EDGE);
845       wrapMode.Clamp(Vector2::ZERO, Vector2(2.f, 2.f));
846       mImpl->mRenderer.RegisterProperty(WRAP_MODE_UNIFORM_NAME, wrapMode);
847     }
848   }
849 }
850
851 void ImageVisual::DoSetOnScene(Actor& actor)
852 {
853   if(mImageUrl.IsValid())
854   {
855     InitializeRenderer();
856   }
857
858   if(!mImpl->mRenderer)
859   {
860     return;
861   }
862
863   mPlacementActor = actor;
864
865   if(mPixelArea != FULL_TEXTURE_RECT)
866   {
867     mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea);
868   }
869
870   if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
871   {
872     actor.AddRenderer(mImpl->mRenderer);
873     mRendererAdded = true;
874     mPlacementActor.Reset();
875
876     // Image loaded and ready to display
877     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
878   }
879   else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
880   {
881     ShowBrokenImage();
882     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
883   }
884   else
885   {
886     if(mFastTrackLoadingTask)
887     {
888       actor.AddRenderer(mImpl->mRenderer);
889       mRendererAdded = true;
890     }
891   }
892 }
893
894 void ImageVisual::DoSetOffScene(Actor& actor)
895 {
896   // Visual::Base::SetOffScene only calls DoSetOffScene if mRenderer exists (is on onstage)
897
898   // Image release is dependent on the ReleasePolicy, renderer is removed.
899   actor.RemoveRenderer(mImpl->mRenderer);
900   mRendererAdded = false;
901
902   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
903   {
904     ResetRenderer();
905   }
906
907   mPlacementActor.Reset();
908 }
909
910 void ImageVisual::DoCreatePropertyMap(Property::Map& map) const
911 {
912   map.Clear();
913   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
914
915   bool sync = IsSynchronousLoadingRequired();
916   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
917   if(mImageUrl.IsValid())
918   {
919     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
920     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
921     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
922   }
923
924   map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode);
925   map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode);
926
927   map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea);
928   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU);
929   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV);
930
931   map.Insert(Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing);
932
933   if(mMaskingData != NULL)
934   {
935     map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl());
936     map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor);
937     map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask);
938     map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
939   }
940
941   map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
942   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
943   map.Insert(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection);
944
945   map.Insert(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, mUseFastTrackUploading);
946 }
947
948 void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
949 {
950   map.Clear();
951   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
952   if(mImageUrl.IsValid())
953   {
954     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
955     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
956   }
957 }
958
959 void ImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
960 {
961   // Check if action is valid for this visual type and perform action if possible
962
963   switch(actionId)
964   {
965     case DevelImageVisual::Action::RELOAD:
966     {
967       auto attemptAtlasing = AttemptAtlasing();
968       LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::FORCED);
969       break;
970     }
971   }
972 }
973
974 void ImageVisual::OnSetTransform()
975 {
976   if(mImpl->mRenderer)
977   {
978     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
979   }
980 }
981
982 void ImageVisual::UpdateShader()
983 {
984   if(mImpl->mRenderer)
985   {
986     Shader shader = GenerateShader();
987     mImpl->mRenderer.SetShader(shader);
988   }
989 }
990
991 // From existing atlas manager
992 void ImageVisual::UploadCompleted()
993 {
994   // Texture has been uploaded. If weak handle is holding a placement actor,
995   // it is the time to add the renderer to actor.
996   Actor actor = mPlacementActor.GetHandle();
997   if(actor)
998   {
999     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
1000     actor.AddRenderer(mImpl->mRenderer);
1001     mRendererAdded = true;
1002     // reset the weak handle so that the renderer only get added to actor once
1003     mPlacementActor.Reset();
1004   }
1005
1006   // Image loaded
1007   ResourceReady(Toolkit::Visual::ResourceStatus::READY);
1008   mLoadState = TextureManager::LoadState::LOAD_FINISHED;
1009 }
1010
1011 // From FastTrackLoadingTask
1012 void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
1013 {
1014   Toolkit::Visual::ResourceStatus resourceStatus;
1015
1016   DALI_ASSERT_ALWAYS(mFastTrackLoadingTask == task && "Task was not canceled successfully!");
1017   DALI_ASSERT_ALWAYS(mRendererAdded && "Some FastTrack logic missed!");
1018
1019   Actor actor = mPlacementActor.GetHandle();
1020
1021   if(mFastTrackLoadingTask && mFastTrackLoadingTask->mLoadSuccess)
1022   {
1023     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1024     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1025
1026     // Change premultiplied alpha flag after change renderer.
1027     EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
1028
1029     if(mFastTrackLoadingTask->mLoadPlanesAvaliable)
1030     {
1031       if(mFastTrackLoadingTask->mPlanesLoaded)
1032       {
1033         // Let we use regular yuv cases.
1034         mNeedYuvToRgb = true;
1035       }
1036       else
1037       {
1038         // Let we use regular image cases.
1039         mNeedYuvToRgb = false;
1040
1041         auto textureSet = mImpl->mRenderer.GetTextures();
1042         DALI_ASSERT_ALWAYS(textureSet && textureSet.GetTextureCount() > 0u && "Previous texture set must exist!");
1043
1044         Dali::TextureSet newTextureSet = TextureSet::New();
1045         newTextureSet.SetTexture(0u, textureSet.GetTexture(0u));
1046         mImpl->mRenderer.SetTextures(newTextureSet);
1047       }
1048
1049       // We can specify what kind of shader we need to use now. Update shader.
1050       mNeedUnifiedYuvAndRgb = false;
1051       UpdateShader();
1052     }
1053   }
1054   else
1055   {
1056     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
1057     mLoadState     = TextureManager::LoadState::LOAD_FAILED;
1058
1059     // Change renderer as broken.
1060     ShowBrokenImage();
1061   }
1062
1063   mFastTrackLoadingTask.Reset();
1064
1065   // Signal to observers ( control ) that resources are ready. Must be all resources.
1066   ResourceReady(resourceStatus);
1067 }
1068
1069 // From Texture Manager
1070 void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
1071 {
1072   Toolkit::Visual::ResourceStatus resourceStatus;
1073   if(mImpl->mRenderer)
1074   {
1075     if(textureInformation.useAtlasing)
1076     {
1077       mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
1078     }
1079
1080     EnablePreMultipliedAlpha(textureInformation.preMultiplied);
1081
1082     Actor actor = mPlacementActor.GetHandle();
1083     if(!loadingSuccess)
1084     {
1085       ShowBrokenImage();
1086       textureInformation.textureSet = mImpl->mRenderer.GetTextures();
1087     }
1088     else
1089     {
1090       if(!textureInformation.useAtlasing)
1091       {
1092         Sampler sampler = Sampler::New();
1093         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
1094         textureInformation.textureSet.SetSampler(0u, sampler);
1095       }
1096
1097       mImpl->mRenderer.SetTextures(textureInformation.textureSet);
1098       ComputeTextureSize();
1099       CheckMaskTexture();
1100
1101       if(textureInformation.textureSet.GetTextureCount() == 3)
1102       {
1103         if(textureInformation.textureSet.GetTexture(0).GetPixelFormat() == Pixel::L8 && textureInformation.textureSet.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && textureInformation.textureSet.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
1104         {
1105           mNeedYuvToRgb = true;
1106           UpdateShader();
1107         }
1108       }
1109
1110       if(actor)
1111       {
1112         actor.AddRenderer(mImpl->mRenderer);
1113         mRendererAdded = true;
1114         // reset the weak handle so that the renderer only get added to actor once
1115         mPlacementActor.Reset();
1116       }
1117     }
1118   }
1119
1120   // Storing TextureSet needed when renderer staged.
1121   if(!mImpl->mRenderer)
1122   {
1123     mTextures = textureInformation.textureSet;
1124   }
1125
1126   // Image loaded, set status regardless of staged status.
1127   if(loadingSuccess)
1128   {
1129     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1130     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1131   }
1132   else
1133   {
1134     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
1135     mLoadState     = TextureManager::LoadState::LOAD_FAILED;
1136   }
1137
1138   // use geometry if needed
1139   if(loadingSuccess)
1140   {
1141     uint32_t firstElementCount{0u};
1142     uint32_t secondElementCount{0u};
1143     auto     geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
1144     if(mImpl->mRenderer && geometry)
1145     {
1146       mImpl->mRenderer.SetGeometry(geometry);
1147       Dali::DevelRenderer::DrawCommand drawCommand{};
1148       drawCommand.drawType = DevelRenderer::DrawType::INDEXED;
1149
1150       if(firstElementCount)
1151       {
1152         drawCommand.firstIndex   = 0;
1153         drawCommand.elementCount = firstElementCount;
1154         drawCommand.queue        = DevelRenderer::RENDER_QUEUE_OPAQUE;
1155         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1156       }
1157
1158       if(secondElementCount)
1159       {
1160         drawCommand.firstIndex   = firstElementCount;
1161         drawCommand.elementCount = secondElementCount;
1162         drawCommand.queue        = DevelRenderer::RENDER_QUEUE_TRANSPARENT;
1163         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1164       }
1165     }
1166   }
1167
1168   // Signal to observers ( control ) that resources are ready. Must be all resources.
1169   ResourceReady(resourceStatus);
1170 }
1171
1172 void ImageVisual::RemoveTexture()
1173 {
1174   if(mTextureId != TextureManager::INVALID_TEXTURE_ID)
1175   {
1176     mFactoryCache.GetTextureManager().RequestRemove(mTextureId, this);
1177     mTextureId = TextureManager::INVALID_TEXTURE_ID;
1178   }
1179   else
1180   {
1181     ResetFastTrackLoadingTask();
1182
1183     Vector4         atlasRect(0.f, 0.f, 1.f, 1.f);
1184     Property::Index index = mImpl->mRenderer.GetPropertyIndex(ATLAS_RECT_UNIFORM_NAME);
1185     if(index != Property::INVALID_INDEX)
1186     {
1187       Property::Value atlasRectValue = mImpl->mRenderer.GetProperty(index);
1188       atlasRectValue.Get(atlasRect);
1189     }
1190
1191     TextureSet textureSet = mImpl->mRenderer.GetTextures();
1192
1193     if(index != Property::INVALID_INDEX)
1194     {
1195       mFactoryCache.GetAtlasManager()->Remove(textureSet, atlasRect);
1196     }
1197   }
1198 }
1199
1200 void ImageVisual::ComputeTextureSize()
1201 {
1202   if(mImpl->mRenderer)
1203   {
1204     auto textureSet = mImpl->mRenderer.GetTextures();
1205     if(textureSet && textureSet.GetTextureCount())
1206     {
1207       auto texture = textureSet.GetTexture(0);
1208       if(texture)
1209       {
1210         mTextureSize.x = texture.GetWidth();
1211         mTextureSize.y = texture.GetHeight();
1212         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1213         {
1214           Texture maskTexture = textureSet.GetTexture(1);
1215           if(maskTexture)
1216           {
1217             mTextureSize.x = std::min(static_cast<uint32_t>(mTextureSize.x * mMaskingData->mContentScaleFactor), maskTexture.GetWidth());
1218             mTextureSize.y = std::min(static_cast<uint32_t>(mTextureSize.y * mMaskingData->mContentScaleFactor), maskTexture.GetHeight());
1219           }
1220         }
1221       }
1222     }
1223   }
1224 }
1225
1226 Vector2 ImageVisual::ComputeMaskTextureRatio()
1227 {
1228   Vector2 maskTextureRatio;
1229   if(mImpl->mRenderer)
1230   {
1231     auto textureSet = mImpl->mRenderer.GetTextures();
1232     if(textureSet && textureSet.GetTextureCount())
1233     {
1234       auto texture = textureSet.GetTexture(0);
1235       if(texture)
1236       {
1237         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1238         {
1239           Texture maskTexture = textureSet.GetTexture(1);
1240           if(maskTexture)
1241           {
1242             float textureWidth  = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1243             float textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1244             maskTextureRatio    = Vector2(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
1245                                        std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
1246           }
1247         }
1248       }
1249     }
1250   }
1251   return maskTextureRatio;
1252 }
1253
1254 Shader ImageVisual::GenerateShader() const
1255 {
1256   Shader shader;
1257
1258   const bool useStandardShader = !mImpl->mCustomShader;
1259   const bool useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
1260
1261   if(useStandardShader)
1262   {
1263     bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false;
1264     // Create and cache the standard shader
1265     shader = mImageVisualShaderFactory.GetShader(
1266       mFactoryCache,
1267       ImageVisualShaderFeature::FeatureBuilder()
1268         .EnableTextureAtlas(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED && !useNativeImage)
1269         .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE)
1270         .EnableRoundedCorner(IsRoundedCornerRequired())
1271         .EnableBorderline(IsBorderlineRequired())
1272         .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
1273         .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)
1274         .EnableYuvToRgb(mNeedYuvToRgb, mNeedUnifiedYuvAndRgb));
1275   }
1276   else
1277   {
1278     bool             usesWholeTexture = true;
1279     std::string_view vertexShaderView;
1280     std::string_view fragmentShaderView;
1281
1282     if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
1283     {
1284       vertexShaderView = mImpl->mCustomShader->mVertexShader;
1285       usesWholeTexture = false; // Impossible to tell.
1286     }
1287     else
1288     {
1289       vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
1290     }
1291
1292     if(mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty())
1293     {
1294       fragmentShaderView = mImpl->mCustomShader->mFragmentShader;
1295     }
1296     else
1297     {
1298       fragmentShaderView = mImageVisualShaderFactory.GetFragmentShaderSource();
1299     }
1300
1301     // If the texture is native, we may need to change prefix and sampler in
1302     // the fragment shader
1303     if(useNativeImage)
1304     {
1305       bool        modifiedFragmentShader = false;
1306       Texture     nativeTexture          = mTextures.GetTexture(0);
1307       std::string fragmentShaderString   = std::string(fragmentShaderView);
1308
1309       modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
1310       if(modifiedFragmentShader)
1311       {
1312         fragmentShaderView = fragmentShaderString;
1313       }
1314
1315       // Create shader here cause fragmentShaderString scope issue
1316       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1317     }
1318     else
1319     {
1320       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1321     }
1322
1323     if(usesWholeTexture)
1324     {
1325       shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
1326     }
1327   }
1328
1329   return shader;
1330 }
1331
1332 void ImageVisual::CheckMaskTexture()
1333 {
1334   if(mMaskingData && !mMaskingData->mPreappliedMasking)
1335   {
1336     bool       maskLoadFailed = true;
1337     TextureSet textures       = mImpl->mRenderer.GetTextures();
1338     if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK)
1339     {
1340       if(mMaskingData->mCropToMask)
1341       {
1342         mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, ComputeMaskTextureRatio());
1343       }
1344       maskLoadFailed = false;
1345     }
1346
1347     if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed)
1348     {
1349       mMaskingData->mMaskImageLoadingFailed = maskLoadFailed;
1350       UpdateShader();
1351     }
1352   }
1353 }
1354
1355 void ImageVisual::ResetRenderer()
1356 {
1357   RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
1358   mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
1359
1360   TextureSet textureSet = TextureSet::New();
1361   mImpl->mRenderer.SetTextures(textureSet);
1362   ComputeTextureSize();
1363
1364   mLoadState = TextureManager::LoadState::NOT_STARTED;
1365 }
1366
1367 void ImageVisual::ShowBrokenImage()
1368 {
1369   if(mEnableBrokenImage)
1370   {
1371     Actor actor = mPlacementActor.GetHandle();
1372
1373     Vector2 imageSize = Vector2::ZERO;
1374     if(actor)
1375     {
1376       imageSize           = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
1377       mPlacementActorSize = imageSize;
1378
1379       if(mRendererAdded)
1380       {
1381         actor.RemoveRenderer(mImpl->mRenderer);
1382         mRendererAdded = false;
1383       }
1384     }
1385
1386     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
1387     if(actor)
1388     {
1389       actor.AddRenderer(mImpl->mRenderer);
1390       mRendererAdded = true;
1391       mPlacementActor.Reset();
1392     }
1393   }
1394   else
1395   {
1396     if(mRendererAdded)
1397     {
1398       Actor actor = mPlacementActor.GetHandle();
1399       if(actor)
1400       {
1401         actor.RemoveRenderer(mImpl->mRenderer);
1402         mRendererAdded = false;
1403       }
1404     }
1405     ResetRenderer();
1406   }
1407 }
1408
1409 void ImageVisual::ResetFastTrackLoadingTask()
1410 {
1411   if(mFastTrackLoadingTask)
1412   {
1413     Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask);
1414     mFastTrackLoadingTask.Reset();
1415   }
1416 }
1417
1418 } // namespace Internal
1419
1420 } // namespace Toolkit
1421
1422 } // namespace Dali