Ambient occlusion support in DLI model
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene-loader / utc-Dali-ShaderDefinitionFactory.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
18 // Enable debug log for test coverage
19 #define DEBUG_ENABLED 1
20
21 #include <dali-test-suite-utils.h>
22 #include <set>
23 #include <string_view>
24 #include "dali-scene-loader/public-api/gltf2-loader.h"
25 #include "dali-scene-loader/public-api/node-definition.h"
26 #include "dali-scene-loader/public-api/resource-bundle.h"
27 #include "dali-scene-loader/public-api/shader-definition-factory.h"
28
29 using namespace Dali;
30 using namespace Dali::SceneLoader;
31
32 namespace
33 {
34 bool EndsWith(const std::string& str, const std::string& suffix) // ends_width() is C++20
35 {
36   return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()).compare(suffix) == 0;
37 }
38
39 MaterialDefinition& NewMaterialDefinition(ResourceBundle& resources)
40 {
41   resources.mMaterials.push_back({});
42   return resources.mMaterials.back().first;
43 }
44
45 MeshDefinition& NewMeshDefinition(ResourceBundle& resources)
46 {
47   resources.mMeshes.push_back({});
48   return resources.mMeshes.back().first;
49 }
50
51 void ClearMeshesAndMaterials(ResourceBundle& resources)
52 {
53   resources.mMaterials.clear();
54   resources.mMeshes.clear();
55 }
56
57 struct Context
58 {
59   ResourceBundle          resources;
60   ShaderDefinitionFactory factory;
61
62   Context()
63   {
64     factory.SetResources(resources);
65   }
66 };
67
68 struct ShaderParameters
69 {
70   MeshDefinition&     meshDef;
71   MaterialDefinition& materialDef;
72   NodeDefinition&     nodeDef;
73 };
74
75 struct Permutation
76 {
77   using ConfigureFn = void (*)(ShaderParameters&);
78
79   ConfigureFn configureFn;
80
81   std::set<std::string> defines;
82   RendererState::Type   rendererStateSet   = 0;
83   RendererState::Type   rendererStateClear = 0;
84 };
85
86 struct PermutationSet
87 {
88   std::vector<const Permutation*> permutations;
89   Index                           shaderIdx;
90 };
91
92 } // namespace
93
94 int UtcDaliShaderDefinitionFactoryProduceShaderInvalid(void)
95 {
96   Context ctx;
97
98   NodeDefinition nodeDef;
99   nodeDef.mRenderable.reset(new NodeDefinition::Renderable());
100
101   DALI_TEST_EQUAL(INVALID_INDEX, ctx.factory.ProduceShader(nodeDef));
102   DALI_TEST_CHECK(ctx.resources.mShaders.empty());
103
104   END_TEST;
105 }
106
107 int UtcDaliShaderDefinitionFactoryProduceShader(void)
108 {
109   Context ctx;
110   ctx.resources.mMaterials.push_back({});
111   ctx.resources.mMeshes.push_back({});
112
113   Permutation permutations[]{
114     {
115       [](ShaderParameters& p) {},
116       {},
117       RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK,
118     },
119     {
120       [](ShaderParameters& p) {
121         p.materialDef.mFlags |= MaterialDefinition::TRANSPARENCY;
122       },
123       {"THREE_TEX"},
124       RendererState::ALPHA_BLEND,
125       RendererState::DEPTH_WRITE,
126     },
127     {[](ShaderParameters& p) {
128        p.materialDef.mTextureStages.push_back({MaterialDefinition::ALBEDO, {}});
129      },
130      {"THREE_TEX"}},
131     {[](ShaderParameters& p) {
132        p.materialDef.mTextureStages.push_back({MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {}});
133      },
134      {"THREE_TEX"}},
135     {[](ShaderParameters& p) {
136        p.materialDef.mTextureStages.push_back({MaterialDefinition::NORMAL, {}});
137      },
138      {"THREE_TEX"}},
139     {[](ShaderParameters& p) {
140        p.materialDef.mFlags |= MaterialDefinition::SUBSURFACE;
141      },
142      {"SSS"}},
143     {[](ShaderParameters& p) {
144        p.materialDef.SetAlphaCutoff(.5f);
145      },
146      {"ALPHA_TEST"}},
147     {[](ShaderParameters& p) {
148        p.materialDef.SetAlphaCutoff(1.f);
149      },
150      {"ALPHA_TEST"}},
151     {[](ShaderParameters& p) {
152        p.materialDef.mFlags |= MaterialDefinition::GLTF_CHANNELS;
153      },
154      {"GLTF_CHANNELS"}},
155     {[](ShaderParameters& p) {
156        p.meshDef.mJoints0.mBlob.mOffset  = 0;
157        p.meshDef.mWeights0.mBlob.mOffset = 0;
158      },
159      {"SKINNING"}},
160     {[](ShaderParameters& p) {
161        p.meshDef.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL;
162      },
163      {"FLIP_V"}},
164     {
165       [](ShaderParameters& p) {
166         p.meshDef.mBlendShapes.push_back({});
167       },
168     },
169     {[](ShaderParameters& p) {
170        p.meshDef.mBlendShapes.back().deltas.mBlob.mOffset = 0;
171      },
172      {"MORPH_POSITION", "MORPH"}},
173     {[](ShaderParameters& p) {
174        p.meshDef.mBlendShapes.back().normals.mBlob.mOffset = 0;
175      },
176      {"MORPH_NORMAL", "MORPH"}},
177     {[](ShaderParameters& p) {
178        p.meshDef.mBlendShapes.back().tangents.mBlob.mOffset = 0;
179      },
180      {"MORPH_TANGENT", "MORPH"}},
181     {[](ShaderParameters& p) {
182        auto& blendShapes = p.meshDef.mBlendShapes;
183        DALI_ASSERT_ALWAYS(!blendShapes.empty() &&
184                           (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID ||
185                            blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID ||
186                            blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID));
187        p.meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
188      },
189      {"MORPH_VERSION_2_0"}},
190
191     {[](ShaderParameters& p) {
192        p.materialDef.mFlags |= MaterialDefinition::OCCLUSION;
193      },
194
195      {"OCCLUSION"}},
196   };
197
198   PermutationSet permSets[]{
199     // default
200     {{&permutations[0]}, 0},
201
202     // alpha
203     {{&permutations[0], &permutations[1]}, 1},
204
205     // three-texture setups
206     {{&permutations[0], &permutations[2]}, 2},
207     {{&permutations[0], &permutations[3]}, 2},
208     {{&permutations[0], &permutations[4]}, 2},
209     {{&permutations[0], &permutations[2], &permutations[3]}, 2},
210     {{&permutations[0], &permutations[3], &permutations[4]}, 2},
211     {{&permutations[0], &permutations[4], &permutations[2]}, 2},
212     {{&permutations[0], &permutations[2], &permutations[3], &permutations[4]}, 2},
213
214     // subsurface scattering
215     {{&permutations[0], &permutations[5]}, 3},
216
217     // alpha test
218     {{&permutations[0], &permutations[6]}, 4},
219     {{&permutations[0], &permutations[7]}, 4},
220
221     // glTF channels
222     {{&permutations[0], &permutations[8]}, 5},
223
224     // skinning
225     {{&permutations[0], &permutations[9]}, 6},
226
227     // flip uvs
228     {{&permutations[0], &permutations[10]}, 7},
229
230     // morphing
231     {{&permutations[0], &permutations[11], &permutations[12]}, 8},
232     {{&permutations[0], &permutations[11], &permutations[13]}, 9},
233     {{&permutations[0], &permutations[11], &permutations[14]}, 10},
234     {{&permutations[0], &permutations[11], &permutations[12], &permutations[13]}, 11},
235     {{&permutations[0], &permutations[11], &permutations[13], &permutations[14]}, 12},
236     {{&permutations[0], &permutations[11], &permutations[14], &permutations[12]}, 13},
237     {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14]}, 14},
238
239     {{&permutations[0], &permutations[11], &permutations[12], &permutations[15]}, 15},
240     {{&permutations[0], &permutations[11], &permutations[13], &permutations[15]}, 16},
241     {{&permutations[0], &permutations[11], &permutations[14], &permutations[15]}, 17},
242     {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15]}, 18},
243     {{&permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15]}, 19},
244     {{&permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15]}, 20},
245     {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15]}, 21},
246
247     // etc.
248     {{&permutations[0], &permutations[1], &permutations[2]}, 1},
249     {{&permutations[0], &permutations[1], &permutations[3]}, 1},
250     {{&permutations[0], &permutations[1], &permutations[2], &permutations[3]}, 1},
251
252     // occlusion
253     {{&permutations[0], &permutations[16]}, 22},
254   };
255
256   for(auto& ps : permSets)
257   {
258     printf("%ld\n", &ps - permSets);
259
260     auto modelNode          = new ModelNode();
261     modelNode->mMeshIdx     = 0;
262     modelNode->mMaterialIdx = 0;
263
264     NodeDefinition nodeDef;
265     nodeDef.mRenderable.reset(modelNode);
266
267     auto&            meshDef     = NewMeshDefinition(ctx.resources);
268     auto&            materialDef = NewMaterialDefinition(ctx.resources);
269     ShaderParameters sp{meshDef, materialDef, nodeDef};
270
271     std::set<std::string> defines;
272     RendererState::Type   rendererState = 0;
273     for(auto p : ps.permutations)
274     {
275       p->configureFn(sp);
276       defines.insert(p->defines.begin(), p->defines.end());
277       rendererState = (rendererState | p->rendererStateSet) & ~p->rendererStateClear;
278     }
279
280     auto shaderIdx = ctx.factory.ProduceShader(nodeDef);
281     DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
282
283     auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
284     DALI_TEST_CHECK(EndsWith(shaderDef.mVertexShaderPath, ".vsh"));
285     DALI_TEST_CHECK(EndsWith(shaderDef.mFragmentShaderPath, ".fsh"));
286     DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
287
288     uint32_t definesUnmatched = shaderDef.mDefines.size();
289     for(auto& d : shaderDef.mDefines)
290     {
291       auto iFind = defines.find(d);
292       if(iFind != defines.end())
293       {
294         defines.erase(iFind);
295         --definesUnmatched;
296       }
297       else
298       {
299         printf("mismatched: %s\n", d.c_str());
300         break;
301       }
302     }
303
304     DALI_TEST_CHECK(defines.empty());
305     DALI_TEST_EQUAL(0, definesUnmatched);
306
307     printf("defines OK\n");
308
309     auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"];
310     DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT);
311
312     auto uCubeMatrix = shaderDef.mUniforms["uCubeMatrix"];
313     DALI_TEST_EQUAL(uCubeMatrix.GetType(), Property::MATRIX);
314
315     ClearMeshesAndMaterials(ctx.resources);
316   }
317
318   END_TEST;
319 }