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