Caching cropToMask in texture manager
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / public-api / shader-definition-factory.cpp
1 /*
2  * Copyright (c) 2022 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::OCCLUSION))
100   {
101     hash.Add("OCCL" /*USION*/);
102   }
103
104   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
105   {
106     hash.Add("GLTF" /*_CHANNELS*/);
107   }
108
109   if(meshDef.IsSkinned())
110   {
111     hash.Add("SKIN" /*NING*/);
112   }
113
114   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
115   {
116     hash.Add("FLIP" /*_V*/);
117   }
118
119   if(meshDef.HasBlendShapes())
120   {
121     bool hasPositions = false;
122     bool hasNormals   = false;
123     bool hasTangents  = false;
124     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
125     if(hasPositions)
126     {
127       hash.Add("MORPHPOS");
128     }
129
130     if(hasNormals)
131     {
132       hash.Add("MORPHNOR");
133     }
134
135     if(hasTangents)
136     {
137       hash.Add("MORPHTAN");
138     }
139
140     if(hasPositions || hasNormals || hasTangents)
141     {
142       hash.Add("MORPH");
143
144       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
145       {
146         hash.Add("MORPHV2");
147       }
148     }
149   }
150
151   return hash;
152 }
153 } // namespace
154
155 struct ShaderDefinitionFactory::Impl
156 {
157   ResourceBundle*           mResources; // no ownership
158   std::map<uint64_t, Index> mShaderMap;
159 };
160
161 ShaderDefinitionFactory::ShaderDefinitionFactory()
162 : mImpl{new Impl()}
163 {
164 }
165
166 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
167
168 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
169 {
170   mImpl->mResources = &resources;
171   mImpl->mShaderMap.clear();
172 }
173
174 Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
175 {
176   DALI_ASSERT_DEBUG(nodeDef.mRenderable);
177
178   auto&            resources = *mImpl->mResources;
179   ResourceReceiver receiver{resources};
180   nodeDef.mRenderable->RegisterResources(receiver);
181   if(!(receiver.mMeshDef && receiver.mMaterialDef))
182   {
183     return INVALID_INDEX;
184   }
185
186   auto&    shaderMap = mImpl->mShaderMap;
187   uint64_t hash      = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
188   auto     iFind     = shaderMap.find(hash);
189   if(iFind != shaderMap.end())
190   {
191     return iFind->second;
192   }
193
194   ShaderDefinition shaderDef;
195   shaderDef.mVertexShaderPath   = PBR_SHADER_NAME + ".vsh";
196   shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
197   shaderDef.mRendererState      = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
198
199   auto&      materialDef     = *receiver.mMaterialDef;
200   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
201   if(hasTransparency)
202   {
203     // TODO: this requires more granularity
204     shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
205   }
206
207   if(hasTransparency ||
208      materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
209      materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
210      materialDef.CheckTextures(MaterialDefinition::NORMAL))
211   {
212     shaderDef.mDefines.push_back("THREE_TEX");
213   }
214
215   if(materialDef.GetAlphaCutoff() > 0.f)
216   {
217     shaderDef.mDefines.push_back("ALPHA_TEST");
218   }
219
220   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
221   {
222     shaderDef.mDefines.push_back("SSS");
223   }
224
225   if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::OCCLUSION))
226   {
227     shaderDef.mDefines.push_back("OCCLUSION");
228   }
229
230   if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
231   {
232     shaderDef.mDefines.push_back("GLTF_CHANNELS");
233   }
234
235   const auto& meshDef = *receiver.mMeshDef;
236   if(meshDef.IsSkinned())
237   {
238     shaderDef.mDefines.push_back("SKINNING");
239   }
240
241   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
242   {
243     shaderDef.mDefines.push_back("FLIP_V");
244   }
245
246   if(meshDef.HasBlendShapes())
247   {
248     bool hasPositions = false;
249     bool hasNormals   = false;
250     bool hasTangents  = false;
251     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
252
253     if(hasPositions)
254     {
255       shaderDef.mDefines.push_back("MORPH_POSITION");
256     }
257
258     if(hasNormals)
259     {
260       shaderDef.mDefines.push_back("MORPH_NORMAL");
261     }
262
263     if(hasTangents)
264     {
265       shaderDef.mDefines.push_back("MORPH_TANGENT");
266     }
267
268     if(hasPositions || hasNormals || hasTangents)
269     {
270       shaderDef.mDefines.push_back("MORPH");
271
272       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
273       {
274         shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
275       }
276     }
277   }
278
279   shaderDef.mUniforms["uMaxLOD"]     = 6.f;
280   shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
281
282   Index result    = resources.mShaders.size();
283   shaderMap[hash] = result;
284
285   resources.mShaders.emplace_back(std::move(shaderDef), Shader());
286
287   return result;
288 }
289
290 } // namespace SceneLoader
291 } // namespace Dali