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 */ /*! 20 * \file glcAggressiveShaderOptimizationsTests.cpp 21 * \brief Conformance tests that checks if shader optimizations are not 22 * overly aggressive. This is done by compering result of complex 23 * trigonometric functions aproximation to shader buil 24 */ /*-------------------------------------------------------------------*/ 25 26#include "glcAggressiveShaderOptimizationsTests.hpp" 27#include "deSharedPtr.hpp" 28#include "glsShaderExecUtil.hpp" 29#include "gluContextInfo.hpp" 30#include "gluDrawUtil.hpp" 31#include "gluPixelTransfer.hpp" 32#include "gluShaderProgram.hpp" 33#include "glwFunctions.hpp" 34#include "tcuImageCompare.hpp" 35#include "tcuRenderTarget.hpp" 36#include "tcuStringTemplate.hpp" 37#include "tcuSurface.hpp" 38#include "tcuTestLog.hpp" 39 40using namespace glw; 41 42namespace glcts 43{ 44 45enum ShaderType 46{ 47 TEST_VERTEX_SHADER, 48 TEST_FRAGMENT_SHADER 49}; 50 51struct TrigonometryCaseData 52{ 53 const char* testedFunction; 54 const char* testedType; 55 const char* colorComponents; 56 ShaderType shaderType; 57}; 58 59class TrigonometryTestCase : public deqp::TestCase 60{ 61public: 62 TrigonometryTestCase(deqp::Context& context, const std::string& name, const TrigonometryCaseData& data); 63 virtual ~TrigonometryTestCase(); 64 65 IterateResult iterate(void); 66 67protected: 68 glu::ProgramSources prepareSineSources(bool useBuiltin); 69 glu::ProgramSources prepareCosineSources(bool useBuiltin); 70 71 void renderAndGrabSurface(glu::ProgramSources sources, tcu::Surface& result) const; 72 73private: 74 ShaderType m_shaderType; 75 const char* m_testedFunction; 76 std::map<std::string, std::string> m_specializationMap; 77}; 78 79TrigonometryTestCase::TrigonometryTestCase(deqp::Context& context, const std::string& name, 80 const TrigonometryCaseData& data) 81 : deqp::TestCase(context, name.c_str(), ""), m_shaderType(data.shaderType), m_testedFunction(data.testedFunction) 82{ 83 glu::ContextType contextType = m_context.getRenderContext().getType(); 84 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType); 85 86 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion); 87 m_specializationMap["TYPE"] = data.testedType; 88 m_specializationMap["COLOR_COMPONENTS"] = data.colorComponents; 89 90 if (glu::contextSupports(contextType, glu::ApiType::es(3, 0)) || glu::isContextTypeGLCore(contextType)) 91 { 92 m_specializationMap["IN"] = "in"; 93 m_specializationMap["OUT"] = "out"; 94 m_specializationMap["ATTRIBUTE"] = "in"; 95 m_specializationMap["FS_OUT_COLOR_NAME"] = "fragColor"; 96 m_specializationMap["FS_OUT_COLOR_DECLARATION"] = "out vec4 fragColor;"; 97 } 98 else 99 { 100 m_specializationMap["IN"] = "varying"; 101 m_specializationMap["OUT"] = "varying"; 102 m_specializationMap["ATTRIBUTE"] = "attribute"; 103 m_specializationMap["FS_OUT_COLOR_NAME"] = "gl_FragColor"; 104 m_specializationMap["FS_OUT_COLOR_DECLARATION"] = ""; 105 } 106} 107 108TrigonometryTestCase::~TrigonometryTestCase() 109{ 110} 111 112glu::ProgramSources TrigonometryTestCase::prepareSineSources(bool useBuiltinSin) 113{ 114 const char* vsDefault = "${VERSION}\n" 115 "${ATTRIBUTE} highp vec2 position;\n" 116 "${ATTRIBUTE} highp vec3 baseColor;\n" 117 "${OUT} vec4 color;\n" 118 "void main (void) {\n" 119 " color = vec4(baseColor, 1.0);\n" 120 " gl_Position = vec4(position, 0.0, 1.0);\n" 121 "}\n"; 122 123 const char* vsCalculateSin = "${VERSION}\n" 124 "${ATTRIBUTE} highp vec2 position;\n" 125 "${ATTRIBUTE} highp vec3 baseColor;\n" 126 "${OUT} vec4 color;\n" 127 "${SIN_FUNCTION_DEFINITION_VS}\n" 128 "void main (void) {\n" 129 " const float M_2PI = 2.0 * 3.14159265358979323846;\n" 130 " ${TYPE} c = baseColor.${COLOR_COMPONENTS} * M_2PI;\n" 131 " ${TYPE} sin_c = ${SIN_FUNCTION_NAME}(c);\n" 132 " \n" 133 " color = vec4(0.0, 0.0, 0.0, 1.0);\n" 134 " color.${COLOR_COMPONENTS} = sin_c * 0.5 + 0.5;\n" 135 " gl_Position = vec4(position, 0.0, 1.0);\n" 136 "}\n"; 137 138 const char* fsDefault = "${VERSION}\n" 139 "precision mediump float;\n" 140 "${IN} vec4 color;\n" 141 "${FS_OUT_COLOR_DECLARATION}\n" 142 "void main (void) {\n" 143 " ${FS_OUT_COLOR_NAME} = color;\n" 144 "}\n"; 145 146 const char* fsCalculateSin = "${VERSION}\n" 147 "precision mediump float;\n" 148 "${IN} vec4 color;\n" 149 "${FS_OUT_COLOR_DECLARATION}\n\n" 150 "${SIN_FUNCTION_DEFINITION_FS}\n" 151 "void main (void) {\n" 152 " const float M_2PI = 2.0 * 3.14159265358979323846;\n" 153 " ${TYPE} c = color.${COLOR_COMPONENTS};\n" 154 " ${TYPE} sin_c = ${SIN_FUNCTION_NAME}(c * M_2PI);\n" 155 " \n" 156 " ${FS_OUT_COLOR_NAME} =vec4(0.0, 0.0, 0.0, 1.0);\n" 157 " ${FS_OUT_COLOR_NAME}.${COLOR_COMPONENTS} = sin_c * 0.5 + 0.5;\n" 158 "}\n"; 159 160 std::string vsTemplate; 161 std::string fsTemplate; 162 163 if (m_shaderType == TEST_VERTEX_SHADER) 164 { 165 vsTemplate = vsCalculateSin; 166 fsTemplate = fsDefault; 167 } 168 else 169 { 170 vsTemplate = vsDefault; 171 fsTemplate = fsCalculateSin; 172 } 173 174 if (useBuiltinSin) 175 { 176 m_specializationMap["SIN_FUNCTION_NAME"] = "sin"; 177 m_specializationMap["SIN_FUNCTION_DEFINITION_VS"] = ""; 178 m_specializationMap["SIN_FUNCTION_DEFINITION_FS"] = ""; 179 } 180 else 181 { 182 std::string sinFunctionDefinitionVS = "${TYPE} ${SIN_FUNCTION_NAME}(${TYPE} c) {\n" 183 " ${TYPE} sin_c = ${TYPE}(0.0);\n" 184 " float sign = 1.0;\n" 185 " float fact;\n" 186 " float fact_of;\n" 187 " \n" 188 " // Taylors series expansion for sin \n" 189 " for(int i = 0; i < 12; i++) {\n" 190 " fact = 1.0;\n" 191 " for(int j = 2; j <= 23; j++)\n" 192 " if (j <= 2 * i + 1)\n" 193 " fact *= float(j);\n" 194 " \n" 195 " sin_c += sign * pow(c, ${TYPE}(2.0 * float(i) + 1.0)) / fact;\n" 196 " sign *= -1.0;\n" 197 " }\n" 198 " return sin_c;\n" 199 "}"; 200 std::string sinFunctionDefinitionFS = "float lerpHelper(float a, float b, float weight) {\n" 201 " return a + (b - a) * weight;\n" 202 "}\n" 203 "float sinLerpHelper(int index, float weight) {\n" 204 " float sArray[17];\n" 205 " sArray[0] = 0.0;\n" 206 " sArray[1] = 0.382683;\n" 207 " sArray[2] = 0.707107;\n" 208 " sArray[3] = 0.92388;\n" 209 " sArray[4] = 1.0;\n" 210 " sArray[5] = 0.92388;\n" 211 " sArray[6] = 0.707107;\n" 212 " sArray[7] = 0.382683;\n" 213 " sArray[8] = 0.0;\n" 214 " sArray[9] = -0.382683;\n" 215 " sArray[10] = -0.707107;\n" 216 " sArray[11] = -0.92388;\n" 217 " sArray[12] = -1.0;\n" 218 " sArray[13] = -0.923879;\n" 219 " sArray[14] = -0.707107;\n" 220 " sArray[15] = -0.382683;\n" 221 " sArray[16] = 0.0;\n" 222 " \n" 223 " if (index == 0)\n" 224 " return lerpHelper(sArray[0], sArray[1], weight);\n" 225 " if (index == 1)\n" 226 " return lerpHelper(sArray[1], sArray[2], weight);\n" 227 " if (index == 2)\n" 228 " return lerpHelper(sArray[2], sArray[3], weight);\n" 229 " if (index == 3)\n" 230 " return lerpHelper(sArray[3], sArray[4], weight);\n" 231 " if (index == 4)\n" 232 " return lerpHelper(sArray[4], sArray[5], weight);\n" 233 " if (index == 5)\n" 234 " return lerpHelper(sArray[5], sArray[6], weight);\n" 235 " if (index == 6)\n" 236 " return lerpHelper(sArray[6], sArray[7], weight);\n" 237 " if (index == 7)\n" 238 " return lerpHelper(sArray[7], sArray[8], weight);\n" 239 " if (index == 8)\n" 240 " return lerpHelper(sArray[8], sArray[9], weight);\n" 241 " if (index == 9)\n" 242 " return lerpHelper(sArray[9], sArray[10], weight);\n" 243 " if (index == 10)\n" 244 " return lerpHelper(sArray[10], sArray[11], weight);\n" 245 " if (index == 11)\n" 246 " return lerpHelper(sArray[11], sArray[12], weight);\n" 247 " if (index == 12)\n" 248 " return lerpHelper(sArray[12], sArray[13], weight);\n" 249 " if (index == 13)\n" 250 " return lerpHelper(sArray[13], sArray[14], weight);\n" 251 " if (index == 14)\n" 252 " return lerpHelper(sArray[14], sArray[15], weight);\n" 253 " if (index == 15)\n" 254 " return lerpHelper(sArray[15], sArray[16], weight);\n" 255 " return sArray[16];\n" 256 "}\n" 257 "${TYPE} ${SIN_FUNCTION_NAME}(${TYPE} c) {\n" 258 " ${TYPE} arrVal = c * 2.546478971;\n" 259 " ${TYPE} weight = arrVal - floor(arrVal);\n" 260 " ${TYPE} sin_c = ${TYPE}(0.0);\n" 261 " ${INTERPOLATE_SIN}" 262 " return sin_c;\n" 263 "}"; 264 265 if (m_specializationMap["TYPE"] == "float") 266 { 267 m_specializationMap["INTERPOLATE_SIN"] = "\n" 268 " int index = int(floor(arrVal));\n" 269 " sin_c = sinLerpHelper(index, weight);\n"; 270 } 271 else if (m_specializationMap["TYPE"] == "vec2") 272 { 273 m_specializationMap["INTERPOLATE_SIN"] = "\n" 274 " int indexX = int(floor(arrVal.x));\n" 275 " sin_c.x = sinLerpHelper(indexX, weight.x);\n" 276 " int indexY = int(floor(arrVal.y));\n" 277 " sin_c.y = sinLerpHelper(indexY, weight.y);\n"; 278 } 279 else if (m_specializationMap["TYPE"] == "vec3") 280 { 281 m_specializationMap["INTERPOLATE_SIN"] = "\n" 282 " int indexX = int(floor(arrVal.x));\n" 283 " sin_c.x = sinLerpHelper(indexX, weight.x);\n" 284 " int indexY = int(floor(arrVal.y));\n" 285 " sin_c.y = sinLerpHelper(indexY, weight.y);\n" 286 " int indexZ = int(floor(arrVal.z));\n" 287 " sin_c.z = sinLerpHelper(indexZ, weight.z);\n"; 288 } 289 290 m_specializationMap["SIN_FUNCTION_NAME"] = "calculateSin"; 291 m_specializationMap["SIN_FUNCTION_DEFINITION_VS"] = 292 tcu::StringTemplate(sinFunctionDefinitionVS).specialize(m_specializationMap); 293 m_specializationMap["SIN_FUNCTION_DEFINITION_FS"] = 294 tcu::StringTemplate(sinFunctionDefinitionFS).specialize(m_specializationMap); 295 } 296 297 // Specialize shader templates 298 vsTemplate = tcu::StringTemplate(vsTemplate).specialize(m_specializationMap); 299 fsTemplate = tcu::StringTemplate(fsTemplate).specialize(m_specializationMap); 300 return glu::makeVtxFragSources(vsTemplate.c_str(), fsTemplate.c_str()); 301} 302 303glu::ProgramSources TrigonometryTestCase::prepareCosineSources(bool useBuiltinCos) 304{ 305 const char* vsDefault = "${VERSION}\n" 306 "${ATTRIBUTE} highp vec2 position;\n" 307 "${ATTRIBUTE} highp vec3 baseColor;\n" 308 "${OUT} vec4 color;\n" 309 "void main (void) {\n" 310 " color = vec4(baseColor, 1.0);\n" 311 " gl_Position = vec4(position, 0.0, 1.0);\n" 312 "}\n"; 313 314 const char* vsCalculateCos = "${VERSION}\n" 315 "${ATTRIBUTE} highp vec2 position;\n" 316 "${ATTRIBUTE} highp vec3 baseColor;\n" 317 "${OUT} vec4 color;\n" 318 "${COS_FUNCTION_DEFINITION_VS}\n" 319 "void main (void) {\n" 320 " const float M_2PI = 2.0 * 3.14159265358979323846;\n" 321 " ${TYPE} c = baseColor.${COLOR_COMPONENTS};\n" 322 " ${TYPE} cos_c = ${COS_FUNCTION_NAME}(c * M_2PI);\n" 323 " \n" 324 " color = vec4(0.0, 0.0, 0.0, 1.0);\n" 325 " color.${COLOR_COMPONENTS} = cos_c * 0.5 + 0.5;\n" 326 " gl_Position = vec4(position, 0.0, 1.0);\n" 327 "}\n"; 328 329 const char* fsDefault = "${VERSION}\n" 330 "precision mediump float;\n" 331 "${IN} vec4 color;\n" 332 "${FS_OUT_COLOR_DECLARATION}\n" 333 "void main (void) {\n" 334 " ${FS_OUT_COLOR_NAME} = color;\n" 335 "}\n"; 336 337 const char* fsCalculateCos = "${VERSION}\n" 338 "precision mediump float;\n" 339 "${IN} vec4 color;\n" 340 "${FS_OUT_COLOR_DECLARATION}\n\n" 341 "// function definitions \n" 342 "${COS_FUNCTION_DEFINITION_FS}\n" 343 "${TYPE} preprocessColor(${TYPE} c) {\n" 344 " ${PREPROCESS_COLOR};\n" 345 " return c;\n" 346 "}\n\n" 347 "void main (void) {\n" 348 " const float M_2PI = 2.0 * 3.14159265358979323846;\n" 349 " ${TYPE} c = preprocessColor(color.${COLOR_COMPONENTS});\n" 350 " ${TYPE} cos_c = ${COS_FUNCTION_NAME}(c * M_2PI);\n" 351 " \n" 352 " ${FS_OUT_COLOR_NAME} = vec4(0.0, 0.0, 0.0, 1.0);\n" 353 " ${FS_OUT_COLOR_NAME}.${COLOR_COMPONENTS} = cos_c * 0.5 + 0.5;\n" 354 "}\n"; 355 356 std::string vsTemplate; 357 std::string fsTemplate; 358 359 if (m_shaderType == TEST_VERTEX_SHADER) 360 { 361 vsTemplate = vsCalculateCos; 362 fsTemplate = fsDefault; 363 } 364 else 365 { 366 vsTemplate = vsDefault; 367 fsTemplate = fsCalculateCos; 368 } 369 370 if (useBuiltinCos) 371 { 372 m_specializationMap["PREPROCESS_COLOR"] = ""; 373 m_specializationMap["COS_FUNCTION_NAME"] = "cos"; 374 m_specializationMap["COS_FUNCTION_DEFINITION_VS"] = ""; 375 m_specializationMap["COS_FUNCTION_DEFINITION_FS"] = ""; 376 } 377 else 378 { 379 std::string cosFunctionDefinitionVS = "${TYPE} ${COS_FUNCTION_NAME}(${TYPE} c) {\n" 380 " ${TYPE} cos_c = ${TYPE}(1.0);\n" 381 " float sign = -1.0;\n" 382 " float fact = 1.0;\n" 383 " \n" 384 " for(int i = 2; i <= 20; i += 2) {\n" 385 " fact *= float(i)*float(i-1);\n" 386 " cos_c += sign*pow(c, ${TYPE}(float(i)))/fact;\n" 387 " sign = -sign;\n" 388 " }\n" 389 " return cos_c;\n" 390 "}"; 391 std::string cosFunctionDefinitionFS = "${TYPE} ${COS_FUNCTION_NAME}(${TYPE} c) {\n" 392 " ${TYPE} cos_c = ${TYPE}(-1.0);\n" 393 " float sign = 1.0;\n" 394 " float fact_even = 1.0;\n" 395 " float fact_odd = 1.0;\n" 396 " ${TYPE} sum;\n" 397 " ${TYPE} exp;\n" 398 " \n" 399 " for(int i = 2; i <= 10; i += 2) {\n" 400 " fact_even *= float(i);\n" 401 " fact_odd *= float(i-1);\n" 402 " exp = ${TYPE}(float(i/2));\n" 403 " sum = sign * pow(abs(c), exp)/fact_even;\n" 404 " cos_c += pow(abs(c), exp)*(sum/fact_odd);\n" 405 " sign = -sign;\n" 406 " }\n" 407 " return cos_c;\n" 408 "}"; 409 410 m_specializationMap["PREPROCESS_COLOR"] = "c = (fract(abs(c)) - 0.5)"; 411 m_specializationMap["COS_FUNCTION_NAME"] = "calculateCos"; 412 m_specializationMap["COS_FUNCTION_DEFINITION_VS"] = 413 tcu::StringTemplate(cosFunctionDefinitionVS).specialize(m_specializationMap); 414 m_specializationMap["COS_FUNCTION_DEFINITION_FS"] = 415 tcu::StringTemplate(cosFunctionDefinitionFS).specialize(m_specializationMap); 416 } 417 418 // Specialize shader templates 419 vsTemplate = tcu::StringTemplate(vsTemplate).specialize(m_specializationMap); 420 fsTemplate = tcu::StringTemplate(fsTemplate).specialize(m_specializationMap); 421 return glu::makeVtxFragSources(vsTemplate.c_str(), fsTemplate.c_str()); 422} 423 424void TrigonometryTestCase::renderAndGrabSurface(glu::ProgramSources sources, tcu::Surface& result) const 425{ 426 static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 427 static const float positions[] = { -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0 }; 428 static const float baseColors[] = { 1.0, 0.0, 0.25, 0.75, 0.25, 1.0, 0.0, 1.0, 0.75, 0.25, 0.5, 0.0 }; 429 430 glu::RenderContext& renderContext = m_context.getRenderContext(); 431 const glw::Functions& gl = renderContext.getFunctions(); 432 glu::ShaderProgram testProgram(renderContext, sources); 433 if (!testProgram.isOk()) 434 { 435 m_testCtx.getLog() << testProgram; 436 TCU_FAIL("Test program compilation failed"); 437 } 438 439 // Render 440 gl.useProgram(testProgram.getProgram()); 441 const glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, positions), 442 glu::va::Float("baseColor", 3, 4, 0, baseColors) }; 443 glu::draw(renderContext, testProgram.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays, 444 glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices)); 445 446 // Grab surface 447 glu::readPixels(renderContext, 0, 0, result.getAccess()); 448} 449 450tcu::TestNode::IterateResult TrigonometryTestCase::iterate(void) 451{ 452 glu::RenderContext& renderContext = m_context.getRenderContext(); 453 const glw::Functions& gl = renderContext.getFunctions(); 454 455 int renderWidth = 64; 456 int renderHeight = 64; 457 if (renderWidth > m_context.getRenderTarget().getWidth()) 458 renderWidth = m_context.getRenderTarget().getWidth(); 459 if (renderHeight > m_context.getRenderTarget().getHeight()) 460 renderHeight = m_context.getRenderTarget().getHeight(); 461 bool isSin = std::string(m_testedFunction) == "sin"; 462 463 gl.viewport(0, 0, renderWidth, renderHeight); 464 465 // Use program that will call trigonometric function aproximation 466 tcu::Surface testSurface(renderWidth, renderHeight); 467 if (isSin) 468 renderAndGrabSurface(prepareSineSources(false), testSurface); 469 else 470 renderAndGrabSurface(prepareCosineSources(false), testSurface); 471 472 // Use reference program that will call builtin function 473 tcu::Surface referenceSurface(renderWidth, renderHeight); 474 if (isSin) 475 renderAndGrabSurface(prepareSineSources(true), referenceSurface); 476 else 477 renderAndGrabSurface(prepareCosineSources(true), referenceSurface); 478 479 // Compare surfaces 480 qpTestResult testResult = QP_TEST_RESULT_FAIL; 481 if (tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", referenceSurface, testSurface, 0.05f, 482 tcu::COMPARE_LOG_RESULT)) 483 testResult = QP_TEST_RESULT_PASS; 484 485 m_testCtx.setTestResult(testResult, qpGetTestResultName(testResult)); 486 return STOP; 487} 488 489AggressiveShaderOptimizationsTests::AggressiveShaderOptimizationsTests(deqp::Context& context) 490 : TestCaseGroup(context, "aggressive_optimizations", "checks if shader optimizations are not overly aggressive") 491{ 492} 493 494AggressiveShaderOptimizationsTests::~AggressiveShaderOptimizationsTests() 495{ 496} 497 498void AggressiveShaderOptimizationsTests::init(void) 499{ 500 TrigonometryCaseData trigonometryCases[] = { 501 { "sin", "float", "r", TEST_VERTEX_SHADER }, { "sin", "float", "r", TEST_FRAGMENT_SHADER }, 502 { "sin", "vec2", "rg", TEST_VERTEX_SHADER }, { "sin", "vec2", "rg", TEST_FRAGMENT_SHADER }, 503 { "sin", "vec3", "rgb", TEST_VERTEX_SHADER }, { "sin", "vec3", "rgb", TEST_FRAGMENT_SHADER }, 504 { "cos", "float", "r", TEST_VERTEX_SHADER }, { "cos", "float", "r", TEST_FRAGMENT_SHADER }, 505 { "cos", "vec2", "rg", TEST_VERTEX_SHADER }, { "cos", "vec2", "rg", TEST_FRAGMENT_SHADER }, 506 { "cos", "vec3", "rgb", TEST_VERTEX_SHADER }, { "cos", "vec3", "rgb", TEST_FRAGMENT_SHADER }, 507 }; 508 509 for (int i = 0; i < DE_LENGTH_OF_ARRAY(trigonometryCases); ++i) 510 { 511 const TrigonometryCaseData& tcd = trigonometryCases[i]; 512 std::string shaderType = (tcd.shaderType == TEST_VERTEX_SHADER) ? "_vert" : "_frag"; 513 std::string name = std::string(tcd.testedFunction) + "_" + tcd.testedType + shaderType; 514 addChild(new TrigonometryTestCase(m_context, name, tcd)); 515 } 516} 517 518} // glcts namespace 519