Merge "Let Anti-Alias consider scale factor" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / shader-manager.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-scene3d/public-api/loader/shader-manager.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <cstring>
25
26 // INTERNAL INCLUDES
27 #include <dali-scene3d/internal/light/light-impl.h>
28 #include <dali-scene3d/internal/loader/hash.h>
29 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
30 #include <dali-scene3d/public-api/loader/node-definition.h>
31
32 #include <dali/integration-api/debug.h>
33
34 namespace
35 {
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_MODEL_SHADER_MANAGER");
38 #endif
39 } // namespace
40
41 namespace Dali::Scene3D::Loader
42 {
43 namespace
44 {
45 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG  = 10;
46 static constexpr uint32_t INDEX_FOR_SHADOW_CONSTRAINT_TAG = 100;
47
48 ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
49 {
50   ShaderOption option;
51
52   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
53   if(hasTransparency)
54   {
55     option.SetTransparency();
56   }
57
58   if(hasTransparency ||
59      !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
60      !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
61   {
62     option.AddOption(ShaderOption::Type::THREE_TEXTURE);
63
64     // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
65     if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
66     {
67       option.AddOption(ShaderOption::Type::BASE_COLOR_TEXTURE);
68     }
69
70     if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
71     {
72       option.AddOption(ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
73     }
74
75     if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
76     {
77       option.AddOption(ShaderOption::Type::NORMAL_TEXTURE);
78     }
79   }
80
81   if(materialDef.GetAlphaCutoff() > 0.f)
82   {
83     option.AddOption(ShaderOption::Type::ALPHA_TEST);
84   }
85
86   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
87   {
88     option.AddOption(ShaderOption::Type::SUBSURFACE);
89   }
90
91   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
92   {
93     option.AddOption(ShaderOption::Type::OCCLUSION);
94   }
95
96   if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
97   {
98     option.AddOption(ShaderOption::Type::EMISSIVE);
99   }
100
101   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
102   {
103     option.AddOption(ShaderOption::Type::SPECULAR);
104   }
105
106   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
107   {
108     option.AddOption(ShaderOption::Type::SPECULAR_COLOR);
109   }
110
111   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
112   {
113     option.AddOption(ShaderOption::Type::GLTF_CHANNELS);
114   }
115
116   if(meshDef.IsSkinned())
117   {
118     option.AddOption(ShaderOption::Type::SKINNING);
119     option.AddJointMacros(meshDef.mJoints.size());
120   }
121
122   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
123   {
124     option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
125   }
126
127   if(!meshDef.mColors.empty() && meshDef.mColors[0].IsDefined())
128   {
129     option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
130   }
131
132   if(meshDef.mTangentType == Property::VECTOR4)
133   {
134     option.AddOption(ShaderOption::Type::VEC4_TANGENT);
135   }
136
137   if(meshDef.HasBlendShapes())
138   {
139     bool hasPositions = false;
140     bool hasNormals   = false;
141     bool hasTangents  = false;
142     meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
143     if(hasPositions)
144     {
145       option.AddOption(ShaderOption::Type::MORPH_POSITION);
146     }
147
148     if(hasNormals)
149     {
150       option.AddOption(ShaderOption::Type::MORPH_NORMAL);
151     }
152
153     if(hasTangents)
154     {
155       option.AddOption(ShaderOption::Type::MORPH_TANGENT);
156     }
157
158     if(hasPositions || hasNormals || hasTangents)
159     {
160       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
161       {
162         option.AddOption(ShaderOption::Type::MORPH_VERSION_2_0);
163       }
164     }
165   }
166
167   return option;
168 }
169 } // namespace
170
171 struct ShaderManager::Impl
172 {
173   std::map<uint64_t, Index>   mShaderMap;
174   std::vector<Dali::Shader>   mShaders;
175   std::vector<Scene3D::Light> mLights;
176
177   Scene3D::Light mShadowLight;
178 };
179
180 ShaderManager::ShaderManager()
181 : mImpl{new Impl()}
182 {
183 }
184
185 ShaderManager::~ShaderManager() = default;
186
187 ShaderOption ShaderManager::ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
188 {
189   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining shader from mat/mesh definitions\n");
190   return MakeOption(materialDefinition, meshDefinition);
191 }
192
193 Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
194 {
195   Dali::Shader result;
196
197   auto&    shaderMap = mImpl->mShaderMap;
198   uint64_t hash      = shaderOption.GetOptionHash();
199
200 #if defined(DEBUG_ENABLED)
201   std::ostringstream oss;
202   oss << "  ShaderOption defines:";
203   std::vector<std::string> defines;
204   shaderOption.GetDefines(defines);
205   for(auto& def : defines)
206   {
207     oss << def << ", ";
208   }
209   oss << std::endl
210       << "  ShaderOption macro definitions:" << std::endl;
211   for(auto& macro : shaderOption.GetMacroDefinitions())
212   {
213     oss << macro.macro << " : " << macro.definition << std::endl;
214   }
215   DALI_LOG_INFO(gLogFilter, Debug::Concise, "ShaderOption:\n%s\n", oss.str().c_str());
216 #endif
217
218   auto iFind = shaderMap.find(hash);
219   if(iFind != shaderMap.end())
220   {
221     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining Shader found: hash: %lx", hash);
222     result = mImpl->mShaders[iFind->second];
223   }
224   else
225   {
226     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Creating new shader: hash: %lx\n", hash);
227     ShaderDefinition shaderDef;
228     shaderDef.mUseBuiltInShader = true;
229
230     shaderOption.GetDefines(shaderDef.mDefines);
231     shaderDef.mMacros                  = shaderOption.GetMacroDefinitions();
232     shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
233
234     shaderMap[hash] = mImpl->mShaders.size();
235
236     auto raw = shaderDef.LoadRaw("");
237     mImpl->mShaders.emplace_back(shaderDef.Load(std::move(raw)));
238     result = mImpl->mShaders.back();
239
240     std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
241     result.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
242
243     for(uint32_t index = 0; index < mImpl->mLights.size(); ++index)
244     {
245       SetLightConstraintToShader(index, result);
246     }
247
248     result.RegisterProperty("uIsShadowEnabled", static_cast<int32_t>(!!mImpl->mShadowLight));
249     if(!!mImpl->mShadowLight)
250     {
251       SetShadowConstraintToShader(result);
252       SetShadowUniformToShader(result);
253     }
254   }
255
256   return result;
257 }
258
259 RendererState::Type ShaderManager::GetRendererState(const MaterialDefinition& materialDefinition)
260 {
261   RendererState::Type rendererState = RendererState::DEPTH_TEST;
262
263   if(!materialDefinition.mDoubleSided)
264   {
265     rendererState |= RendererState::CULL_BACK;
266   }
267
268   const bool hasTransparency = MaskMatch(materialDefinition.mFlags, MaterialDefinition::TRANSPARENCY);
269   if(hasTransparency)
270   {
271     // TODO: this requires more granularity
272     rendererState = (rendererState | RendererState::ALPHA_BLEND);
273   }
274   return rendererState;
275 }
276
277 bool ShaderManager::AddLight(Scene3D::Light light)
278 {
279   if(!light || mImpl->mLights.size() >= Scene3D::Internal::Light::GetMaximumEnabledLightCount())
280   {
281     return false;
282   }
283
284   uint32_t lightIndex = mImpl->mLights.size();
285   mImpl->mLights.push_back(light);
286
287   for(auto&& shader : mImpl->mShaders)
288   {
289     std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
290     shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
291   }
292
293   SetLightConstraint(lightIndex);
294
295   return true;
296 }
297
298 void ShaderManager::RemoveLight(Scene3D::Light light)
299 {
300   uint32_t lightCount = mImpl->mLights.size();
301   for(uint32_t index = 0; index < lightCount; ++index)
302   {
303     if(mImpl->mLights[index] != light)
304     {
305       continue;
306     }
307
308     RemoveLightConstraint(index);
309
310     if(!mImpl->mLights.empty() && light != mImpl->mLights.back())
311     {
312       RemoveLightConstraint(mImpl->mLights.size() - 1);
313       mImpl->mLights[index] = mImpl->mLights.back();
314       SetLightConstraint(index);
315     }
316
317     mImpl->mLights.pop_back();
318
319     for(auto&& shader : mImpl->mShaders)
320     {
321       std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
322       shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
323     }
324     break;
325   }
326 }
327
328 uint32_t ShaderManager::GetLightCount() const
329 {
330   return mImpl->mLights.size();
331 }
332
333 void ShaderManager::SetShadow(Scene3D::Light light)
334 {
335   mImpl->mShadowLight = light;
336   for(auto&& shader : mImpl->mShaders)
337   {
338     std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
339     shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(true));
340   }
341
342   SetShadowProperty();
343 }
344
345 void ShaderManager::RemoveShadow()
346 {
347   for(auto&& shader : mImpl->mShaders)
348   {
349     std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
350     shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(false));
351     shader.RemoveConstraints(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
352   }
353   mImpl->mShadowLight.Reset();
354 }
355
356 void ShaderManager::UpdateShadowUniform(Scene3D::Light light)
357 {
358   if(light != mImpl->mShadowLight)
359   {
360     return;
361   }
362
363   for(auto&& shader : mImpl->mShaders)
364   {
365     SetShadowUniformToShader(shader);
366   }
367 }
368
369 void ShaderManager::SetLightConstraint(uint32_t lightIndex)
370 {
371   for(auto&& shader : mImpl->mShaders)
372   {
373     SetLightConstraintToShader(lightIndex, shader);
374   }
375 }
376
377 void ShaderManager::SetLightConstraintToShader(uint32_t lightIndex, Dali::Shader shader)
378 {
379   std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
380   lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
381   auto             lightDirectionPropertyIndex = shader.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
382   Dali::Constraint lightDirectionConstraint    = Dali::Constraint::New<Vector3>(shader, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
383   lightDirectionConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::WORLD_ORIENTATION});
384   lightDirectionConstraint.ApplyPost();
385   lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
386
387   std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
388   lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
389   auto             lightColorPropertyIndex = shader.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
390   Dali::Constraint lightColorConstraint    = Dali::Constraint::New<Vector3>(shader, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = Vector3(inputs[0]->GetVector4()); });
391   lightColorConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::COLOR});
392   lightColorConstraint.ApplyPost();
393   lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
394 }
395
396 void ShaderManager::RemoveLightConstraint(uint32_t lightIndex)
397 {
398   for(auto&& shader : mImpl->mShaders)
399   {
400     shader.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
401   }
402 }
403
404 void ShaderManager::SetShadowUniformToShader(Dali::Shader shader)
405 {
406   shader.RegisterProperty("uShadowIntensity", mImpl->mShadowLight.GetShadowIntensity());
407   shader.RegisterProperty("uShadowBias", mImpl->mShadowLight.GetShadowBias());
408   shader.RegisterProperty("uEnableShadowSoftFiltering", static_cast<int>(mImpl->mShadowLight.IsShadowSoftFilteringEnabled()));
409 }
410
411 void ShaderManager::SetShadowProperty()
412 {
413   for(auto&& shader : mImpl->mShaders)
414   {
415     SetShadowUniformToShader(shader);
416     SetShadowConstraintToShader(shader);
417   }
418 }
419
420 void ShaderManager::SetShadowConstraintToShader(Dali::Shader shader)
421 {
422   // Constraint is applied before View/Projection Matrix is computed in update thread.
423   // So, it could show not plausible result if camera properties are changed discontinuesly.
424   // If we want to make it be synchronized, View/Projection matrix are needed to be conputed in below constraint.
425
426   std::string       shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName());
427   auto              shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY);
428   Dali::CameraActor shadowLightCamera                 = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera();
429   auto              tempViewProjectionMatrixIndex     = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
430   if(tempViewProjectionMatrixIndex != Dali::Property::INVALID_INDEX)
431   {
432     tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
433   }
434   Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetMatrix(); });
435   shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewProjectionMatrixIndex});
436   shadowViewProjectionConstraint.ApplyPost();
437   shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
438 }
439
440 } // namespace Dali::Scene3D::Loader