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 34using namespace deqp::gls::ShaderExecUtil; 35 36namespace glcts 37{ 38 39namespace ShaderConstExpr 40{ 41 42struct 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 58struct 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 72template <typename OutputType> 73class ExecutorTestCase : public deqp::TestCase 74{ 75public: 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 81protected: 82 void validateOutput(de::SharedPtr<ShaderExecutor> executor); 83 84 glu::ShaderType m_shaderType; 85 ShaderSpec m_shaderSpec; 86 OutputType m_expectedOutput; 87}; 88 89template <typename OutputType> 90ExecutorTestCase<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 99template <typename OutputType> 100ExecutorTestCase<OutputType>::~ExecutorTestCase(void) 101{ 102} 103 104template <> 105void 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 127template <> 128void 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 145template <typename OutputType> 146tcu::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 177template <typename OutputType> 178void 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 235void 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 315ShaderConstExprTests::ShaderConstExprTests(deqp::Context& context) 316 : deqp::TestCaseGroup(context, "constant_expressions", "Constant expressions") 317{ 318} 319 320ShaderConstExprTests::~ShaderConstExprTests(void) 321{ 322} 323 324void 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