[dali_2.1.0] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image-visual-shader-factory.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
19
20 // EXTERNAL INCLUDES
21 #include <dali/devel-api/rendering/texture-devel.h>
22
23 // INTERNAL INCLUDES
24 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
25 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30 namespace Toolkit
31 {
32 namespace Internal
33 {
34 namespace
35 {
36 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
37
38 // global string variable to caching complate vertex shader
39 static std::string gVertexShader;
40
41 // global string variable to caching complate fragment shader (no atlas)
42 static std::string gFragmentShaderNoAtlas;
43
44 const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
45
46 } // unnamed namespace
47
48 namespace ImageVisualShaderFeature
49 {
50 FeatureBuilder& FeatureBuilder::EnableTextureAtlas(bool enableAtlas)
51 {
52   mTextureAtlas = (enableAtlas ? TextureAtlas::ENABLED : TextureAtlas::DISABLED);
53   return *this;
54 }
55 FeatureBuilder& FeatureBuilder::ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode)
56 {
57   mDefaultTextureWrapMode = (applyDefaultTextureWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY);
58   return *this;
59 }
60 FeatureBuilder& FeatureBuilder::EnableRoundedCorner(bool enableRoundedCorner)
61 {
62   mRoundedCorner = (enableRoundedCorner ? RoundedCorner::ENABLED : RoundedCorner::DISABLED);
63   return *this;
64 }
65 FeatureBuilder& FeatureBuilder::EnableBorderline(bool enableBorderline)
66 {
67   mBorderline = (enableBorderline ? Borderline::ENABLED : Borderline::DISABLED);
68   return *this;
69 }
70 FeatureBuilder& FeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Texture& texture)
71 {
72   mTexture = texture;
73   return *this;
74 }
75 } // namespace ImageVisualShaderFeature
76
77 ImageVisualShaderFactory::ImageVisualShaderFactory()
78 : mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
79 {
80 }
81
82 ImageVisualShaderFactory::~ImageVisualShaderFactory()
83 {
84 }
85
86 Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, const ImageVisualShaderFeature::FeatureBuilder& featureBuilder)
87 {
88   Shader shader;
89   VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
90
91   const auto& atlasing               = featureBuilder.mTextureAtlas;
92   const auto& defaultTextureWrapping = featureBuilder.mDefaultTextureWrapMode;
93   const auto& roundedCorner          = featureBuilder.mRoundedCorner;
94   const auto& borderline             = featureBuilder.mBorderline;
95   const auto& changeFragmentShader   = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture))
96                                        ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
97                                        : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
98
99   if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
100   {
101     if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
102     {
103       shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
104     }
105     else
106     {
107       shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
108     }
109   }
110   else
111   {
112     if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
113     {
114       if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
115       {
116         shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
117       }
118       else
119       {
120         shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER;
121       }
122     }
123     else
124     {
125       if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
126       {
127         shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
128       }
129     }
130   }
131
132   if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE &&
133      (mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED ||
134       mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE))
135   {
136     shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) + NATIVE_SHADER_TYPE_OFFSET);
137   }
138
139   shader = factoryCache.GetShader(shaderType);
140   if(!shader)
141   {
142     std::string vertexShaderPrefixList;
143     std::string fragmentShaderPrefixList;
144     if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
145     {
146       if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
147       {
148         fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n";
149       }
150       else
151       {
152         fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n";
153       }
154     }
155     else
156     {
157       if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
158       {
159         vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
160         fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
161       }
162       if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
163       {
164         vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
165         fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
166       }
167     }
168
169     std::string vertexShader   = std::string(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
170     std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
171
172     if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
173     {
174       if(DALI_UNLIKELY(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED))
175       {
176         // NOTE : This routine will run exist one times.
177         //
178         // First, we will run ApplyNativeFragmentShader
179         //  - If fragment shader is modified, then current platform allow to change fragment shader.
180         //    We cache this result mFragmentShaderNeedChange = ChangeFragmentShader::NEED_CHANGE.
181         //  - If fragment shader is not modified, then current platform will always don't change fragment shader.
182         //    We cache this result mFragmentShaderNeedChange = ChangeFragmentShader::DONT_CHANGE.
183         //    And change current shaderType into normal image range.
184         //    After cached the result, shaderType never become NATIVE_IMAGE_SHADER anymore.
185         // Second, save shader result.
186
187         // Try to apply fragmentShader
188         bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.mTexture, fragmentShader);
189         if(modified)
190         {
191           // Now we know that fragment shader need to change.
192           mFragmentShaderNeedChange = ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE;
193         }
194         else
195         {
196           // Now we know that fragment shader even don't need to change.
197           // We can skip ApplyNativeFragmentShader routine after now.
198           mFragmentShaderNeedChange = ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
199
200           // Now we need normal shader type
201           // So decrease NATIVE_SHADER_TYPE_OFFSET.
202           shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) - NATIVE_SHADER_TYPE_OFFSET);
203
204           // If we already compiled this type already, just use that cached shader.
205           // Else, just go forward.
206           shader = factoryCache.GetShader(shaderType);
207           if(shader)
208           {
209             return shader;
210           }
211         }
212       }
213       else if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
214       {
215         // Always need to apply fragmentShader
216         bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.mTexture, fragmentShader);
217         DALI_ASSERT_ALWAYS(modified && "NativeImageTexture need to change fragment shader. But DALI default image shader doesn't changed!");
218       }
219     }
220     shader = Shader::New(vertexShader, fragmentShader);
221     shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
222     factoryCache.SaveShader(shaderType, shader);
223   }
224
225   return shader;
226 }
227
228 std::string_view ImageVisualShaderFactory::GetVertexShaderSource()
229 {
230   if(gVertexShader.empty())
231   {
232     gVertexShader = Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data();
233   }
234
235   return gVertexShader;
236 }
237
238 std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
239 {
240   if(gFragmentShaderNoAtlas.empty())
241   {
242     gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
243   }
244   return gFragmentShaderNoAtlas;
245 }
246
247 } // namespace Internal
248
249 } // namespace Toolkit
250
251 } // namespace Dali