xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcShaderConstExprTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * \file  glcShaderConstExprTests.cpp
20  * \brief Declares shader constant expressions tests.
21  */ /*-------------------------------------------------------------------*/
22 
23 #include "glcShaderConstExprTests.hpp"
24 #include "deMath.h"
25 #include "deSharedPtr.hpp"
26 #include "glsShaderExecUtil.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluShaderUtil.hpp"
29 #include "tcuFloat.hpp"
30 #include "tcuStringTemplate.hpp"
31 #include "tcuTestLog.hpp"
32 #include <map>
33 
34 using namespace deqp::gls::ShaderExecUtil;
35 
36 namespace glcts
37 {
38 
39 namespace ShaderConstExpr
40 {
41 
42 struct TestParams
43 {
44     const char *name;
45     const char *expression;
46 
47     glu::DataType inType;
48     int minComponents;
49     int maxComponents;
50 
51     glu::DataType outType;
52     union
53     {
54         float outputFloat;
55         int outputInt;
56     };
57 };
58 
59 struct ShaderExecutorParams
60 {
61     deqp::Context *context;
62 
63     std::string caseName;
64     std::string source;
65 
66     glu::DataType outType;
67     union
68     {
69         float outputFloat;
70         int outputInt;
71     };
72 };
73 
74 template <typename OutputType>
75 class ExecutorTestCase : public deqp::TestCase
76 {
77 public:
78     ExecutorTestCase(deqp::Context &context, const char *name, glu::ShaderType shaderType, const ShaderSpec &shaderSpec,
79                      OutputType expectedOutput);
80     virtual ~ExecutorTestCase(void);
81     virtual tcu::TestNode::IterateResult iterate(void);
82 
83 protected:
84     void validateOutput(de::SharedPtr<ShaderExecutor> executor);
85 
86     glu::ShaderType m_shaderType;
87     ShaderSpec m_shaderSpec;
88     OutputType m_expectedOutput;
89 };
90 
91 template <typename OutputType>
ExecutorTestCase(deqp::Context & context,const char * name,glu::ShaderType shaderType,const ShaderSpec & shaderSpec,OutputType expectedOutput)92 ExecutorTestCase<OutputType>::ExecutorTestCase(deqp::Context &context, const char *name, glu::ShaderType shaderType,
93                                                const ShaderSpec &shaderSpec, OutputType expectedOutput)
94     : deqp::TestCase(context, name, "")
95     , m_shaderType(shaderType)
96     , m_shaderSpec(shaderSpec)
97     , m_expectedOutput(expectedOutput)
98 {
99 }
100 
101 template <typename OutputType>
~ExecutorTestCase(void)102 ExecutorTestCase<OutputType>::~ExecutorTestCase(void)
103 {
104 }
105 
106 template <>
validateOutput(de::SharedPtr<ShaderExecutor> executor)107 void ExecutorTestCase<float>::validateOutput(de::SharedPtr<ShaderExecutor> executor)
108 {
109     float result        = 0.0f;
110     void *const outputs = &result;
111     executor->execute(1, DE_NULL, &outputs);
112 
113     const float epsilon = 0.01f;
114     if (de::abs(m_expectedOutput - result) > epsilon)
115     {
116         m_context.getTestContext().getLog()
117             << tcu::TestLog::Message << "Expected: " << m_expectedOutput << " ("
118             << tcu::toHex(tcu::Float32(m_expectedOutput).bits()) << ") but constant expresion returned: " << result
119             << " (" << tcu::toHex(tcu::Float32(result).bits()) << "), used " << epsilon << " epsilon for comparison"
120             << tcu::TestLog::EndMessage;
121         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
122         return;
123     }
124 
125     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
126     return;
127 }
128 
129 template <>
validateOutput(de::SharedPtr<ShaderExecutor> executor)130 void ExecutorTestCase<int>::validateOutput(de::SharedPtr<ShaderExecutor> executor)
131 {
132     int result          = 0;
133     void *const outputs = &result;
134     executor->execute(1, DE_NULL, &outputs);
135 
136     if (result == m_expectedOutput)
137     {
138         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
139         return;
140     }
141 
142     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Expected: " << m_expectedOutput
143                                         << " but constant expresion returned: " << result << tcu::TestLog::EndMessage;
144     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
145 }
146 
147 template <typename OutputType>
iterate(void)148 tcu::TestNode::IterateResult ExecutorTestCase<OutputType>::iterate(void)
149 {
150     de::SharedPtr<ShaderExecutor> executor(createExecutor(m_context.getRenderContext(), m_shaderType, m_shaderSpec));
151 
152     DE_ASSERT(executor.get());
153 
154     executor->log(m_context.getTestContext().getLog());
155 
156     try
157     {
158         if (!executor->isOk())
159             TCU_FAIL("Compilation failed");
160 
161         executor->useProgram();
162 
163         validateOutput(executor);
164     }
165     catch (const tcu::NotSupportedError &e)
166     {
167         m_testCtx.getLog() << tcu::TestLog::Message << e.what() << tcu::TestLog::EndMessage;
168         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, e.getMessage());
169     }
170     catch (const tcu::TestError &e)
171     {
172         m_testCtx.getLog() << tcu::TestLog::Message << e.what() << tcu::TestLog::EndMessage;
173         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage());
174     }
175 
176     return tcu::TestNode::STOP;
177 }
178 
179 template <typename OutputType>
createTestCasesForAllShaderTypes(const ShaderExecutorParams & params,std::vector<tcu::TestNode * > & outputTests)180 void createTestCasesForAllShaderTypes(const ShaderExecutorParams &params, std::vector<tcu::TestNode *> &outputTests)
181 {
182     DE_ASSERT(params.context);
183 
184     deqp::Context &context       = *(params.context);
185     glu::ContextType contextType = context.getRenderContext().getType();
186 
187     ShaderSpec shaderSpec;
188     shaderSpec.version = glu::getContextTypeGLSLVersion(contextType);
189     shaderSpec.source  = params.source;
190     shaderSpec.outputs.push_back(Symbol("out0", glu::VarType(params.outType, glu::PRECISION_HIGHP)));
191 
192     // Construct list of shaders for which tests can be created
193     std::vector<glu::ShaderType> shaderTypes;
194 
195     if (glu::contextSupports(contextType, glu::ApiType::core(4, 3)))
196     {
197         shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
198         shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
199         shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
200         shaderTypes.push_back(glu::SHADERTYPE_GEOMETRY);
201         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_CONTROL);
202         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_EVALUATION);
203     }
204     else if (glu::contextSupports(contextType, glu::ApiType::es(3, 2)))
205     {
206         shaderSpec.version = glu::GLSL_VERSION_320_ES;
207         shaderTypes.push_back(glu::SHADERTYPE_GEOMETRY);
208         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_CONTROL);
209         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_EVALUATION);
210     }
211     else if (glu::contextSupports(contextType, glu::ApiType::es(3, 1)))
212     {
213         shaderSpec.version = glu::GLSL_VERSION_310_ES;
214         shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
215         shaderTypes.push_back(glu::SHADERTYPE_GEOMETRY);
216         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_CONTROL);
217         shaderTypes.push_back(glu::SHADERTYPE_TESSELLATION_EVALUATION);
218     }
219     else
220     {
221         shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
222         shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
223     }
224 
225     shaderSpec.globalDeclarations += "precision highp float;\n";
226 
227     for (std::size_t typeIndex = 0; typeIndex < shaderTypes.size(); ++typeIndex)
228     {
229         glu::ShaderType shaderType = shaderTypes[typeIndex];
230         std::string caseName(params.caseName + '_' + getShaderTypeName(shaderType));
231 
232         outputTests.push_back(new ExecutorTestCase<OutputType>(context, caseName.c_str(), shaderType, shaderSpec,
233                                                                static_cast<OutputType>(params.outputFloat)));
234     }
235 }
236 
createTests(deqp::Context & context,const TestParams * cases,int numCases,const char * shaderTemplateSrc,const char * casePrefix,std::vector<tcu::TestNode * > & outputTests)237 void createTests(deqp::Context &context, const TestParams *cases, int numCases, const char *shaderTemplateSrc,
238                  const char *casePrefix, std::vector<tcu::TestNode *> &outputTests)
239 {
240     const tcu::StringTemplate shaderTemplate(shaderTemplateSrc);
241     const char *componentAccess[] = {"", ".y", ".z", ".w"};
242 
243     ShaderExecutorParams shaderExecutorParams;
244     shaderExecutorParams.context = &context;
245 
246     for (int caseIndex = 0; caseIndex < numCases; caseIndex++)
247     {
248         const TestParams &testCase   = cases[caseIndex];
249         const std::string baseName   = testCase.name;
250         const int minComponents      = testCase.minComponents;
251         const int maxComponents      = testCase.maxComponents;
252         const glu::DataType inType   = testCase.inType;
253         const std::string expression = testCase.expression;
254 
255         // Check for presence of func(vec, scalar) style specialization,
256         // use as gatekeeper for applying said specialization
257         const bool alwaysScalar = expression.find("${MT}") != std::string::npos;
258 
259         std::map<std::string, std::string> shaderTemplateParams;
260         shaderTemplateParams["CASE_BASE_TYPE"] = glu::getDataTypeName(testCase.outType);
261 
262         shaderExecutorParams.outType     = testCase.outType;
263         shaderExecutorParams.outputFloat = testCase.outputFloat;
264 
265         for (int component = minComponents - 1; component < maxComponents; component++)
266         {
267             // Get type name eg. float, vec2, vec3, vec4 (same for other primitive types)
268             glu::DataType dataType = static_cast<glu::DataType>(inType + component);
269             std::string typeName   = glu::getDataTypeName(dataType);
270 
271             // ${T} => final type, ${MT} => final type but with scalar version usable even when T is a vector
272             std::map<std::string, std::string> expressionTemplateParams;
273             expressionTemplateParams["T"]  = typeName;
274             expressionTemplateParams["MT"] = typeName;
275 
276             const tcu::StringTemplate expressionTemplate(expression);
277 
278             // Add vector access to expression as needed
279             shaderTemplateParams["CASE_EXPRESSION"] =
280                 expressionTemplate.specialize(expressionTemplateParams) + componentAccess[component];
281 
282             {
283                 // Add type to case name if we are generating multiple versions
284                 shaderExecutorParams.caseName = (casePrefix + baseName);
285                 if (minComponents != maxComponents)
286                     shaderExecutorParams.caseName += ("_" + typeName);
287 
288                 shaderExecutorParams.source = shaderTemplate.specialize(shaderTemplateParams);
289                 if (shaderExecutorParams.outType == glu::TYPE_FLOAT)
290                     createTestCasesForAllShaderTypes<float>(shaderExecutorParams, outputTests);
291                 else
292                     createTestCasesForAllShaderTypes<int>(shaderExecutorParams, outputTests);
293             }
294 
295             // Deal with functions that allways accept one ore more scalar parameters even when others are vectors
296             if (alwaysScalar && component > 0)
297             {
298                 shaderExecutorParams.caseName =
299                     casePrefix + baseName + "_" + typeName + "_" + glu::getDataTypeName(inType);
300 
301                 expressionTemplateParams["MT"] = glu::getDataTypeName(inType);
302                 shaderTemplateParams["CASE_EXPRESSION"] =
303                     expressionTemplate.specialize(expressionTemplateParams) + componentAccess[component];
304 
305                 shaderExecutorParams.source = shaderTemplate.specialize(shaderTemplateParams);
306                 if (shaderExecutorParams.outType == glu::TYPE_FLOAT)
307                     createTestCasesForAllShaderTypes<float>(shaderExecutorParams, outputTests);
308                 else
309                     createTestCasesForAllShaderTypes<int>(shaderExecutorParams, outputTests);
310             }
311         } // component loop
312     }
313 }
314 
315 } // namespace ShaderConstExpr
316 
ShaderConstExprTests(deqp::Context & context)317 ShaderConstExprTests::ShaderConstExprTests(deqp::Context &context)
318     : deqp::TestCaseGroup(context, "constant_expressions", "Constant expressions")
319 {
320 }
321 
~ShaderConstExprTests(void)322 ShaderConstExprTests::~ShaderConstExprTests(void)
323 {
324 }
325 
init(void)326 void ShaderConstExprTests::init(void)
327 {
328     // Needed for autogenerating shader code for increased component counts
329     DE_STATIC_ASSERT(glu::TYPE_FLOAT + 1 == glu::TYPE_FLOAT_VEC2);
330     DE_STATIC_ASSERT(glu::TYPE_FLOAT + 2 == glu::TYPE_FLOAT_VEC3);
331     DE_STATIC_ASSERT(glu::TYPE_FLOAT + 3 == glu::TYPE_FLOAT_VEC4);
332 
333     DE_STATIC_ASSERT(glu::TYPE_INT + 1 == glu::TYPE_INT_VEC2);
334     DE_STATIC_ASSERT(glu::TYPE_INT + 2 == glu::TYPE_INT_VEC3);
335     DE_STATIC_ASSERT(glu::TYPE_INT + 3 == glu::TYPE_INT_VEC4);
336 
337     DE_STATIC_ASSERT(glu::TYPE_UINT + 1 == glu::TYPE_UINT_VEC2);
338     DE_STATIC_ASSERT(glu::TYPE_UINT + 2 == glu::TYPE_UINT_VEC3);
339     DE_STATIC_ASSERT(glu::TYPE_UINT + 3 == glu::TYPE_UINT_VEC4);
340 
341     DE_STATIC_ASSERT(glu::TYPE_BOOL + 1 == glu::TYPE_BOOL_VEC2);
342     DE_STATIC_ASSERT(glu::TYPE_BOOL + 2 == glu::TYPE_BOOL_VEC3);
343     DE_STATIC_ASSERT(glu::TYPE_BOOL + 3 == glu::TYPE_BOOL_VEC4);
344 
345     // ${T} => final type, ${MT} => final type but with scalar version usable even when T is a vector
346     const ShaderConstExpr::TestParams baseCases[] = {
347         {"radians", "radians(${T} (90.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatRadians(90.0f)}},
348         {"degrees", "degrees(${T} (2.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatDegrees(2.0f)}},
349         {"sin", "sin(${T} (3.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatSin(3.0f)}},
350         {"cos", "cos(${T} (3.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatCos(3.2f)}},
351         {"asin", "asin(${T} (0.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatAsin(0.0f)}},
352         {"acos", "acos(${T} (1.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatAcos(1.0f)}},
353         {"pow", "pow(${T} (1.7), ${T} (3.5))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatPow(1.7f, 3.5f)}},
354         {"exp", "exp(${T} (4.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatExp(4.2f)}},
355         {"log", "log(${T} (42.12))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatLog(42.12f)}},
356         {"exp2", "exp2(${T} (6.7))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatExp2(6.7f)}},
357         {"log2", "log2(${T} (100.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatLog2(100.0f)}},
358         {"sqrt", "sqrt(${T} (10.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatSqrt(10.0f)}},
359         {"inversesqrt", "inversesqrt(${T} (10.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatRsq(10.0f)}},
360         {"abs", "abs(${T} (-42))", glu::TYPE_INT, 1, 4, glu::TYPE_INT, {42}},
361         {"sign", "sign(${T} (-18.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {-1.0f}},
362         {"floor", "floor(${T} (37.3))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatFloor(37.3f)}},
363         {"trunc", "trunc(${T} (-1.8))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {-1.0f}},
364         {"round", "round(${T} (42.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {42.0f}},
365         {"ceil", "ceil(${T} (82.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatCeil(82.2f)}},
366         {"mod", "mod(${T} (87.65), ${MT} (3.7))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {deFloatMod(87.65f, 3.7f)}},
367         {"min", "min(${T} (12.3), ${MT} (32.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {12.3f}},
368         {"max", "max(${T} (12.3), ${MT} (32.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {32.1f}},
369         {"clamp", "clamp(${T} (42.1), ${MT} (10.0), ${MT} (15.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_FLOAT, {15.0f}},
370         {"length_float", "length(1.0)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {1.0f}},
371         {"length_vec2", "length(vec2(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatSqrt(2.0f)}},
372         {"length_vec3", "length(vec3(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatSqrt(3.0f)}},
373         {"length_vec4", "length(vec4(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatSqrt(4.0f)}},
374         {"dot_float", "dot(1.0, 1.0)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {1.0f}},
375         {"dot_vec2", "dot(vec2(1.0), vec2(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {2.0f}},
376         {"dot_vec3", "dot(vec3(1.0), vec3(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {3.0f}},
377         {"dot_vec4", "dot(vec4(1.0), vec4(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {4.0f}},
378         {"normalize_float", "normalize(1.0)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {1.0f}},
379         {"normalize_vec2", "normalize(vec2(1.0)).x", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatRsq(2.0f)}},
380         {"normalize_vec3", "normalize(vec3(1.0)).x", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatRsq(3.0f)}},
381         {"normalize_vec4", "normalize(vec4(1.0)).x", glu::TYPE_FLOAT, 1, 1, glu::TYPE_FLOAT, {deFloatRsq(4.0f)}},
382     };
383 
384     const ShaderConstExpr::TestParams arrayCases[] = {
385         {"radians", "radians(${T} (60.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatRadians(60.0f)}},
386         {"degrees", "degrees(${T} (0.11))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatDegrees(0.11f)}},
387         {"sin", "${T} (1.0) + sin(${T} (0.7))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {1.0f + deFloatSin(0.7f)}},
388         {"cos", "${T} (1.0) + cos(${T} (0.7))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {1.0f + deFloatCos(0.7f)}},
389         {"asin", "asin(${T} (0.9))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatAsin(0.9f)}},
390         {"acos", "acos(${T} (-0.5))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatAcos(-0.5f)}},
391         {"pow", "pow(${T} (2.0), ${T} (2.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatPow(2.0f, 2.0f)}},
392         {"exp", "exp(${T} (1.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatExp(1.2f)}},
393         {"log", "log(${T} (8.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatLog(8.0f)}},
394         {"exp2", "exp2(${T} (2.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatExp2(2.1f)}},
395         {"log2", "log2(${T} (9.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatLog2(9.0)}},
396         {"sqrt", "sqrt(${T} (4.5))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatSqrt(4.5f)}},
397         {"inversesqrt", "inversesqrt(${T} (0.26))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatRsq(0.26f)}},
398         {"abs", "abs(${T} (-2))", glu::TYPE_INT, 1, 4, glu::TYPE_INT, {2}},
399         {"sign", "sign(${T} (18.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatSign(18.0f)}},
400         {"floor", "floor(${T} (3.3))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatFloor(3.3f)}},
401         {"trunc", "trunc(${T} (2.8))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {2}},
402         {"round", "round(${T} (2.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatRound(2.2f)}},
403         {"ceil", "ceil(${T} (2.2))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatCeil(2.2f)}},
404         {"mod", "mod(${T} (7.1), ${MT} (4.0))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatMod(7.1f, 4.0f)}},
405         {"min", "min(${T} (2.3), ${MT} (3.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatMin(2.3f, 3.1f)}},
406         {"max", "max(${T} (2.3), ${MT} (3.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {deFloatMax(2.3f, 3.1f)}},
407         {"clamp", "clamp(${T} (4.1), ${MT} (2.1), ${MT} (3.1))", glu::TYPE_FLOAT, 1, 4, glu::TYPE_INT, {3}},
408         {"length_float", "length(2.1)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {2}},
409         {"length_vec2", "length(vec2(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {deFloatSqrt(2.0f)}},
410         {"length_vec3", "length(vec3(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {deFloatSqrt(3.0f)}},
411         {"length_vec4", "length(vec4(1.0))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {deFloatSqrt(4.0f)}},
412         {"dot_float", "dot(1.0, 1.0)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {1}},
413         {"dot_vec2", "dot(vec2(1.0), vec2(1.01))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {2}},
414         {"dot_vec3", "dot(vec3(1.0), vec3(1.1))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {3}},
415         {"dot_vec4", "dot(vec4(1.0), vec4(1.1))", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {4}},
416         {"normalize_float", "${T} (1.0) + normalize(2.0)", glu::TYPE_FLOAT, 1, 1, glu::TYPE_INT, {2}},
417         {"normalize_vec2",
418          "${T} (1.0) + normalize(vec2(1.0)).x",
419          glu::TYPE_FLOAT,
420          1,
421          1,
422          glu::TYPE_INT,
423          {1.0f + deFloatRsq(2.0f)}},
424         {"normalize_vec3",
425          "${T} (1.0) + normalize(vec3(1.0)).x",
426          glu::TYPE_FLOAT,
427          1,
428          1,
429          glu::TYPE_INT,
430          {1.0f + deFloatRsq(3.0f)}},
431         {"normalize_vec4",
432          "${T} (1.0) + normalize(vec4(1.0)).x",
433          glu::TYPE_FLOAT,
434          1,
435          1,
436          glu::TYPE_INT,
437          {1.0f + deFloatRsq(4.0f)}},
438     };
439 
440     const char *basicShaderTemplate = "const ${CASE_BASE_TYPE} cval = ${CASE_EXPRESSION};\n"
441                                       "out0 = cval;\n";
442 
443     std::vector<tcu::TestNode *> children;
444     ShaderConstExpr::createTests(m_context, baseCases, DE_LENGTH_OF_ARRAY(baseCases), basicShaderTemplate, "basic_",
445                                  children);
446 
447     const char *arrayShaderTemplate = "float array[int(${CASE_EXPRESSION})];\n"
448                                       "out0 = array.length();\n";
449 
450     ShaderConstExpr::createTests(m_context, arrayCases, DE_LENGTH_OF_ARRAY(arrayCases), arrayShaderTemplate, "array_",
451                                  children);
452 
453     for (std::size_t i = 0; i < children.size(); i++)
454         addChild(children[i]);
455 }
456 
457 } // namespace glcts
458