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
40 using namespace glw;
41
42 namespace glcts
43 {
44
45 enum ShaderType
46 {
47 TEST_VERTEX_SHADER,
48 TEST_FRAGMENT_SHADER
49 };
50
51 struct TrigonometryCaseData
52 {
53 const char* testedFunction;
54 const char* testedType;
55 const char* colorComponents;
56 ShaderType shaderType;
57 };
58
59 class TrigonometryTestCase : public deqp::TestCase
60 {
61 public:
62 TrigonometryTestCase(deqp::Context& context, const std::string& name, const TrigonometryCaseData& data);
63 virtual ~TrigonometryTestCase();
64
65 IterateResult iterate(void);
66
67 protected:
68 glu::ProgramSources prepareSineSources(bool useBuiltin);
69 glu::ProgramSources prepareCosineSources(bool useBuiltin);
70
71 void renderAndGrabSurface(glu::ProgramSources sources, tcu::Surface& result) const;
72
73 private:
74 ShaderType m_shaderType;
75 const char* m_testedFunction;
76 std::map<std::string, std::string> m_specializationMap;
77 };
78
TrigonometryTestCase(deqp::Context & context,const std::string & name,const TrigonometryCaseData & data)79 TrigonometryTestCase::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
~TrigonometryTestCase()108 TrigonometryTestCase::~TrigonometryTestCase()
109 {
110 }
111
prepareSineSources(bool useBuiltinSin)112 glu::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
prepareCosineSources(bool useBuiltinCos)303 glu::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
renderAndGrabSurface(glu::ProgramSources sources,tcu::Surface & result) const424 void 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
iterate(void)450 tcu::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
AggressiveShaderOptimizationsTests(deqp::Context & context)489 AggressiveShaderOptimizationsTests::AggressiveShaderOptimizationsTests(deqp::Context& context)
490 : TestCaseGroup(context, "aggressive_optimizations", "checks if shader optimizations are not overly aggressive")
491 {
492 }
493
~AggressiveShaderOptimizationsTests()494 AggressiveShaderOptimizationsTests::~AggressiveShaderOptimizationsTests()
495 {
496 }
497
init(void)498 void 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