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