Enhance texteditor background drawing performance
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / public-api / shader-definition-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 #include "dali-scene-loader/public-api/shader-definition-factory.h"
18 #include <cstring>
19 #include "dali-scene-loader/internal/hash.h"
20 #include "dali-scene-loader/public-api/blend-shape-details.h"
21 #include "dali-scene-loader/public-api/node-definition.h"
22 #include "dali/devel-api/common/map-wrapper.h"
23
24 namespace Dali
25 {
26 namespace SceneLoader
27 {
28 namespace
29 {
30 struct ResourceReceiver : IResourceReceiver
31 {
32   const ResourceBundle&     mResources;
33   const MeshDefinition*     mMeshDef     = nullptr;
34   const MaterialDefinition* mMaterialDef = nullptr;
35
36   ResourceReceiver(const ResourceBundle& resources)
37   : mResources(resources)
38   {
39   }
40
41   void Register(ResourceType::Value type, Index id) override
42   {
43     switch(type)
44     {
45       case ResourceType::Mesh:
46         mMeshDef = &mResources.mMeshes[id].first;
47         break;
48
49       case ResourceType::Material:
50         mMaterialDef = &mResources.mMaterials[id].first;
51         break;
52
53       default:
54         break;
55     }
56   }
57 };
58
59 const std::string PBR_SHADER_NAME = "dli_pbr";
60
61 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
62 {
63   for(const auto& blendShape : blendShapes)
64   {
65     hasPositions = hasPositions || blendShape.deltas.IsDefined();
66     hasNormals   = hasNormals || blendShape.normals.IsDefined();
67     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
68   }
69 }
70
71 uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
72 {
73   Hash hash;
74
75   // note: could be per vertex / fragment component - in WatchViewer, these have the same name.
76   hash.Add(PBR_SHADER_NAME);
77
78   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
79   hash.Add(hasTransparency);
80
81   if(hasTransparency ||
82      materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
83      materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
84      materialDef.CheckTextures(MaterialDefinition::NORMAL))
85   {
86     hash.Add("3TEX");
87   }
88
89   if(materialDef.GetAlphaCutoff() > 0.f)
90   {
91     hash.Add("ALPH" /*A_TEST*/);
92   }
93
94   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
95   {
96     hash.Add("SSS");
97   }
98
99   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
100   {
101     hash.Add("GLTF" /*_CHANNELS*/);
102   }
103
104   if(meshDef.IsSkinned())
105   {
106     hash.Add("SKIN" /*NING*/);
107   }
108
109   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
110   {
111     hash.Add("FLIP" /*_V*/);
112   }
113
114   if(meshDef.HasBlendShapes())
115   {
116     bool hasPositions = false;
117     bool hasNormals   = false;
118     bool hasTangents  = false;
119     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
120     if(hasPositions)
121     {
122       hash.Add("MORPHPOS");
123     }
124
125     if(hasNormals)
126     {
127       hash.Add("MORPHNOR");
128     }
129
130     if(hasTangents)
131     {
132       hash.Add("MORPHTAN");
133     }
134
135     if(hasPositions || hasNormals || hasTangents)
136     {
137       hash.Add("MORPH");
138
139       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
140       {
141         hash.Add("MORPHV2");
142       }
143     }
144   }
145
146   return hash;
147 }
148 } // namespace
149
150 struct ShaderDefinitionFactory::Impl
151 {
152   ResourceBundle*           mResources; // no ownership
153   std::map<uint64_t, Index> mShaderMap;
154 };
155
156 ShaderDefinitionFactory::ShaderDefinitionFactory()
157 : mImpl{new Impl()}
158 {
159 }
160
161 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
162
163 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
164 {
165   mImpl->mResources = &resources;
166   mImpl->mShaderMap.clear();
167 }
168
169 Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
170 {
171   DALI_ASSERT_DEBUG(nodeDef.mRenderable);
172
173   auto&            resources = *mImpl->mResources;
174   ResourceReceiver receiver{resources};
175   nodeDef.mRenderable->RegisterResources(receiver);
176   if(!(receiver.mMeshDef && receiver.mMaterialDef))
177   {
178     return INVALID_INDEX;
179   }
180
181   auto&    shaderMap = mImpl->mShaderMap;
182   uint64_t hash      = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
183   auto     iFind     = shaderMap.find(hash);
184   if(iFind != shaderMap.end())
185   {
186     return iFind->second;
187   }
188
189   ShaderDefinition shaderDef;
190   shaderDef.mVertexShaderPath   = PBR_SHADER_NAME + ".vsh";
191   shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
192   shaderDef.mRendererState      = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
193
194   auto&      materialDef     = *receiver.mMaterialDef;
195   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
196   if(hasTransparency)
197   {
198     // TODO: this requires more granularity
199     shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
200   }
201
202   if(hasTransparency ||
203      materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
204      materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
205      materialDef.CheckTextures(MaterialDefinition::NORMAL))
206   {
207     shaderDef.mDefines.push_back("THREE_TEX");
208   }
209
210   if(materialDef.GetAlphaCutoff() > 0.f)
211   {
212     shaderDef.mDefines.push_back("ALPHA_TEST");
213   }
214
215   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
216   {
217     shaderDef.mDefines.push_back("SSS");
218   }
219
220   if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
221   {
222     shaderDef.mDefines.push_back("GLTF_CHANNELS");
223   }
224
225   const auto& meshDef = *receiver.mMeshDef;
226   if(meshDef.IsSkinned())
227   {
228     shaderDef.mDefines.push_back("SKINNING");
229   }
230
231   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
232   {
233     shaderDef.mDefines.push_back("FLIP_V");
234   }
235
236   if(meshDef.HasBlendShapes())
237   {
238     bool hasPositions = false;
239     bool hasNormals   = false;
240     bool hasTangents  = false;
241     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
242
243     if(hasPositions)
244     {
245       shaderDef.mDefines.push_back("MORPH_POSITION");
246     }
247
248     if(hasNormals)
249     {
250       shaderDef.mDefines.push_back("MORPH_NORMAL");
251     }
252
253     if(hasTangents)
254     {
255       shaderDef.mDefines.push_back("MORPH_TANGENT");
256     }
257
258     if(hasPositions || hasNormals || hasTangents)
259     {
260       shaderDef.mDefines.push_back("MORPH");
261
262       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
263       {
264         shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
265       }
266     }
267   }
268
269   shaderDef.mUniforms["uMaxLOD"]     = 6.f;
270   shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
271
272   Index result    = resources.mShaders.size();
273   shaderMap[hash] = result;
274
275   resources.mShaders.emplace_back(std::move(shaderDef), Shader());
276
277   return result;
278 }
279
280 } // namespace SceneLoader
281 } // namespace Dali