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