1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL Shared Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
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
21 * \brief Shared shader constant expression test components
22 *//*--------------------------------------------------------------------*/
23
24#include "glsShaderConstExprTests.hpp"
25#include "glsShaderLibrary.hpp"
26#include "glsShaderLibraryCase.hpp"
27
28#include "tcuStringTemplate.hpp"
29
30#include "deStringUtil.hpp"
31#include "deMath.h"
32
33namespace deqp
34{
35namespace gls
36{
37namespace ShaderConstExpr
38{
39
40std::vector<tcu::TestNode*> createTests (tcu::TestContext&			testContext,
41										 glu::RenderContext&		renderContext,
42										 const glu::ContextInfo&	contextInfo,
43										 const TestParams*			cases,
44										 int						numCases,
45										 glu::GLSLVersion			version,
46										 TestShaderStage			testStage)
47{
48	using std::string;
49	using std::vector;
50	using gls::sl::ShaderCase;
51
52	// Needed for autogenerating shader code for increased component counts
53	DE_STATIC_ASSERT(glu::TYPE_FLOAT+1 == glu::TYPE_FLOAT_VEC2);
54	DE_STATIC_ASSERT(glu::TYPE_FLOAT+2 == glu::TYPE_FLOAT_VEC3);
55	DE_STATIC_ASSERT(glu::TYPE_FLOAT+3 == glu::TYPE_FLOAT_VEC4);
56
57	DE_STATIC_ASSERT(glu::TYPE_INT+1 == glu::TYPE_INT_VEC2);
58	DE_STATIC_ASSERT(glu::TYPE_INT+2 == glu::TYPE_INT_VEC3);
59	DE_STATIC_ASSERT(glu::TYPE_INT+3 == glu::TYPE_INT_VEC4);
60
61	DE_STATIC_ASSERT(glu::TYPE_UINT+1 == glu::TYPE_UINT_VEC2);
62	DE_STATIC_ASSERT(glu::TYPE_UINT+2 == glu::TYPE_UINT_VEC3);
63	DE_STATIC_ASSERT(glu::TYPE_UINT+3 == glu::TYPE_UINT_VEC4);
64
65	DE_STATIC_ASSERT(glu::TYPE_BOOL+1 == glu::TYPE_BOOL_VEC2);
66	DE_STATIC_ASSERT(glu::TYPE_BOOL+2 == glu::TYPE_BOOL_VEC3);
67	DE_STATIC_ASSERT(glu::TYPE_BOOL+3 == glu::TYPE_BOOL_VEC4);
68
69	DE_ASSERT(testStage);
70
71	const char* shaderTemplateSrc =
72		"#version ${GLES_VERSION}\n"
73		"precision highp float;\n"
74		"precision highp int;\n"
75		"${DECLARATIONS}\n"
76		"void main()\n"
77		"{\n"
78		"	const ${CASE_BASE_TYPE} cval = ${CASE_EXPRESSION};\n"
79		"	out0 = cval;\n"
80		"	${OUTPUT}\n"
81		"}\n";
82
83	const tcu::StringTemplate		shaderTemplate	(shaderTemplateSrc);
84	vector<tcu::TestNode*>			ret;
85	vector<ShaderCase::ValueBlock>	shaderOutput	(1);
86
87	shaderOutput[0].arrayLength = 1;
88	shaderOutput[0].values.push_back(ShaderCase::Value());
89	shaderOutput[0].values[0].storageType		= ShaderCase::Value::STORAGE_OUTPUT;
90	shaderOutput[0].values[0].valueName			= "out0";
91	shaderOutput[0].values[0].dataType			= glu::TYPE_FLOAT;
92	shaderOutput[0].values[0].arrayLength		= 1;
93	shaderOutput[0].values[0].elements.push_back(ShaderCase::Value::Element());
94
95	for (int caseNdx = 0; caseNdx < numCases; caseNdx++)
96	{
97		std::map<string, string>	shaderTemplateParams;
98		const int					minComponents	= cases[caseNdx].minComponents;
99		const int					maxComponents	= cases[caseNdx].maxComponents;
100		const DataType				inType			= cases[caseNdx].inType;
101		const DataType				outType			= cases[caseNdx].outType;
102		const string				expression		= cases[caseNdx].expression;
103		// Check for presence of func(vec, scalar) style specialization, use as gatekeeper for applying said specialization
104		const bool					alwaysScalar	= expression.find("${MT}")!=string::npos;
105		ShaderCase::Value&			expected		= shaderOutput[0].values[0];
106
107		switch (outType)
108		{
109			case glu::TYPE_INT:
110				expected.elements[0].int32 = (int)cases[caseNdx].output;
111				break;
112
113			case glu::TYPE_UINT:
114				expected.elements[0].int32 = (unsigned int)cases[caseNdx].output;
115				break;
116
117			case glu::TYPE_BOOL:
118				expected.elements[0].bool32 = cases[caseNdx].output!=0.0f;
119				break;
120
121			case glu::TYPE_FLOAT:
122				expected.elements[0].float32 = cases[caseNdx].output;
123				break;
124
125			default:
126				DE_ASSERT(false);
127		}
128
129		expected.dataType = outType;
130
131		shaderTemplateParams["GLES_VERSION"]	= version == glu::GLSL_VERSION_300_ES ? "300 es" : "100";
132		shaderTemplateParams["CASE_BASE_TYPE"]	= glu::getDataTypeName(outType);
133		shaderTemplateParams["DECLARATIONS"]	= "${DECLARATIONS}";
134		shaderTemplateParams["OUTPUT"]			= "${OUTPUT}";
135
136		for (int compCount = minComponents-1; compCount < maxComponents; compCount++)
137		{
138			vector<tcu::TestNode*>		children;
139			std::map<string, string>	expressionTemplateParams;
140			string						typeName			= glu::getDataTypeName((glu::DataType)(inType + compCount)); // results in float, vec2, vec3, vec4 progression (same for other primitive types)
141			const char*					componentAccess[]	= {"", ".y", ".z", ".w"};
142			const tcu::StringTemplate	expressionTemplate	(expression);
143			// Add type to case name if we are generating multiple versions
144			const string				caseName			= string(cases[caseNdx].name) + (minComponents==maxComponents ? "" : ("_" + typeName));
145
146			// ${T} => final type, ${MT} => final type but with scalar version usable even when T is a vector
147			expressionTemplateParams["T"]			= typeName;
148			expressionTemplateParams["MT"]			= typeName;
149
150			shaderTemplateParams["CASE_EXPRESSION"]	= expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount]; // Add vector access to expression as needed
151
152			{
153				const string mapped = shaderTemplate.specialize(shaderTemplateParams);
154
155				if (testStage & SHADER_VERTEX)
156					ret.push_back(new ShaderCase(testContext,
157												 renderContext,
158												 contextInfo,
159												 (caseName + "_vertex").c_str(),
160												 "",
161												 ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase(ShaderCase::EXPECT_PASS,
162																													 version,
163																													 shaderOutput,
164																													 mapped)));
165
166				if (testStage & SHADER_FRAGMENT)
167					ret.push_back(new ShaderCase(testContext,
168												 renderContext,
169												 contextInfo,
170												 (caseName + "_fragment").c_str(),
171												 "",
172												 ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase(ShaderCase::EXPECT_PASS,
173																													   version,
174																													   shaderOutput,
175																													   mapped)));
176			}
177
178			// Deal with functions that allways accept one ore more scalar parameters even when others are vectors
179			if (alwaysScalar && compCount > 0)
180			{
181				const string	scalarCaseName	= string(cases[caseNdx].name) + "_" + typeName + "_" + glu::getDataTypeName(inType);
182
183				expressionTemplateParams["MT"] = glu::getDataTypeName(inType);
184				shaderTemplateParams["CASE_EXPRESSION"]	= expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount];
185
186				{
187					const string mapped = shaderTemplate.specialize(shaderTemplateParams);
188
189					if (testStage & SHADER_VERTEX)
190						ret.push_back(new ShaderCase(testContext,
191													 renderContext,
192													 contextInfo,
193													 (scalarCaseName + "_vertex").c_str(),
194													 "",
195													 ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase(ShaderCase::EXPECT_PASS,
196																														 version,
197																														 shaderOutput,
198																														 mapped)));
199
200					if (testStage & SHADER_FRAGMENT)
201						ret.push_back(new ShaderCase(testContext,
202													 renderContext,
203													 contextInfo,
204													 (scalarCaseName + "_fragment").c_str(),
205													 "",
206													 ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase(ShaderCase::EXPECT_PASS,
207																														   version,
208																														   shaderOutput,
209																														   mapped)));
210				}
211			}
212		}
213	}
214
215	return ret;
216}
217
218} // ShaderConstExpr
219} // gls
220} // deqp
221