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
40static void addOutputVar (glu::sl::ValueBlock* dst, glu::DataType type, float output)
41{
42	dst->outputs.push_back(glu::sl::Value());
43
44	{
45		glu::sl::Value&	value	= dst->outputs.back();
46
47		value.name	= "out0";
48		value.type	= glu::VarType(type, glu::PRECISION_LAST);
49		value.elements.resize(1);
50
51		switch (type)
52		{
53			case glu::TYPE_INT:
54				value.elements[0].int32 = (int)output;
55				break;
56
57			case glu::TYPE_UINT:
58				value.elements[0].int32 = (unsigned int)output;
59				break;
60
61			case glu::TYPE_BOOL:
62				value.elements[0].bool32 = output!=0.0f;
63				break;
64
65			case glu::TYPE_FLOAT:
66				value.elements[0].float32 = output;
67				break;
68
69			default:
70				DE_ASSERT(false);
71		}
72	}
73}
74
75std::vector<tcu::TestNode*> createTests (tcu::TestContext&			testContext,
76										 glu::RenderContext&		renderContext,
77										 const glu::ContextInfo&	contextInfo,
78										 const TestParams*			cases,
79										 int						numCases,
80										 glu::GLSLVersion			version,
81										 TestShaderStage			testStage)
82{
83	using std::string;
84	using std::vector;
85	using gls::ShaderLibraryCase;
86
87	// Needed for autogenerating shader code for increased component counts
88	DE_STATIC_ASSERT(glu::TYPE_FLOAT+1 == glu::TYPE_FLOAT_VEC2);
89	DE_STATIC_ASSERT(glu::TYPE_FLOAT+2 == glu::TYPE_FLOAT_VEC3);
90	DE_STATIC_ASSERT(glu::TYPE_FLOAT+3 == glu::TYPE_FLOAT_VEC4);
91
92	DE_STATIC_ASSERT(glu::TYPE_INT+1 == glu::TYPE_INT_VEC2);
93	DE_STATIC_ASSERT(glu::TYPE_INT+2 == glu::TYPE_INT_VEC3);
94	DE_STATIC_ASSERT(glu::TYPE_INT+3 == glu::TYPE_INT_VEC4);
95
96	DE_STATIC_ASSERT(glu::TYPE_UINT+1 == glu::TYPE_UINT_VEC2);
97	DE_STATIC_ASSERT(glu::TYPE_UINT+2 == glu::TYPE_UINT_VEC3);
98	DE_STATIC_ASSERT(glu::TYPE_UINT+3 == glu::TYPE_UINT_VEC4);
99
100	DE_STATIC_ASSERT(glu::TYPE_BOOL+1 == glu::TYPE_BOOL_VEC2);
101	DE_STATIC_ASSERT(glu::TYPE_BOOL+2 == glu::TYPE_BOOL_VEC3);
102	DE_STATIC_ASSERT(glu::TYPE_BOOL+3 == glu::TYPE_BOOL_VEC4);
103
104	DE_ASSERT(testStage);
105
106	const char* shaderTemplateSrc =
107		"#version ${GLES_VERSION}\n"
108		"precision highp float;\n"
109		"precision highp int;\n"
110		"${DECLARATIONS}\n"
111		"void main()\n"
112		"{\n"
113		"	const ${CASE_BASE_TYPE} cval = ${CASE_EXPRESSION};\n"
114		"	out0 = cval;\n"
115		"	${OUTPUT}\n"
116		"}\n";
117
118	const tcu::StringTemplate	shaderTemplate	(shaderTemplateSrc);
119	vector<tcu::TestNode*>		ret;
120
121	for (int caseNdx = 0; caseNdx < numCases; caseNdx++)
122	{
123		std::map<string, string>	shaderTemplateParams;
124		const int					minComponents	= cases[caseNdx].minComponents;
125		const int					maxComponents	= cases[caseNdx].maxComponents;
126		const DataType				inType			= cases[caseNdx].inType;
127		const DataType				outType			= cases[caseNdx].outType;
128		const string				expression		= cases[caseNdx].expression;
129		// Check for presence of func(vec, scalar) style specialization, use as gatekeeper for applying said specialization
130		const bool					alwaysScalar	= expression.find("${MT}")!=string::npos;
131
132		shaderTemplateParams["GLES_VERSION"]	= version == glu::GLSL_VERSION_300_ES ? "300 es" : "100";
133		shaderTemplateParams["CASE_BASE_TYPE"]	= glu::getDataTypeName(outType);
134		shaderTemplateParams["DECLARATIONS"]	= "${DECLARATIONS}";
135		shaderTemplateParams["OUTPUT"]			= "${OUTPUT}";
136
137		for (int compCount = minComponents-1; compCount < maxComponents; compCount++)
138		{
139			vector<tcu::TestNode*>		children;
140			std::map<string, string>	expressionTemplateParams;
141			string						typeName			= glu::getDataTypeName((glu::DataType)(inType + compCount)); // results in float, vec2, vec3, vec4 progression (same for other primitive types)
142			const char*					componentAccess[]	= {"", ".y", ".z", ".w"};
143			const tcu::StringTemplate	expressionTemplate	(expression);
144			// Add type to case name if we are generating multiple versions
145			const string				caseName			= string(cases[caseNdx].name) + (minComponents==maxComponents ? "" : ("_" + typeName));
146
147			// ${T} => final type, ${MT} => final type but with scalar version usable even when T is a vector
148			expressionTemplateParams["T"]			= typeName;
149			expressionTemplateParams["MT"]			= typeName;
150
151			shaderTemplateParams["CASE_EXPRESSION"]	= expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount]; // Add vector access to expression as needed
152
153			{
154				const string mapped = shaderTemplate.specialize(shaderTemplateParams);
155
156				if (testStage & SHADER_VERTEX)
157				{
158					glu::sl::ShaderCaseSpecification	spec;
159
160					spec.targetVersion	= version;
161					spec.expectResult	= glu::sl::EXPECT_PASS;
162					spec.caseType		= glu::sl::CASETYPE_VERTEX_ONLY;
163					spec.programs.resize(1);
164
165					spec.programs[0].sources << glu::VertexSource(mapped);
166
167					addOutputVar(&spec.values, outType, cases[caseNdx].output);
168
169					ret.push_back(new ShaderLibraryCase(testContext,
170														renderContext,
171														contextInfo,
172														(caseName + "_vertex").c_str(),
173														"",
174														spec));
175				}
176
177				if (testStage & SHADER_FRAGMENT)
178				{
179					glu::sl::ShaderCaseSpecification	spec;
180
181					spec.targetVersion	= version;
182					spec.expectResult	= glu::sl::EXPECT_PASS;
183					spec.caseType		= glu::sl::CASETYPE_FRAGMENT_ONLY;
184					spec.programs.resize(1);
185
186					spec.programs[0].sources << glu::FragmentSource(mapped);
187
188					addOutputVar(&spec.values, outType, cases[caseNdx].output);
189
190					ret.push_back(new ShaderLibraryCase(testContext,
191														renderContext,
192														contextInfo,
193														(caseName + "_fragment").c_str(),
194														"",
195														spec));
196				}
197			}
198
199			// Deal with functions that allways accept one ore more scalar parameters even when others are vectors
200			if (alwaysScalar && compCount > 0)
201			{
202				const string	scalarCaseName	= string(cases[caseNdx].name) + "_" + typeName + "_" + glu::getDataTypeName(inType);
203
204				expressionTemplateParams["MT"] = glu::getDataTypeName(inType);
205				shaderTemplateParams["CASE_EXPRESSION"]	= expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount];
206
207				{
208					const string mapped = shaderTemplate.specialize(shaderTemplateParams);
209
210					if (testStage & SHADER_VERTEX)
211					{
212						glu::sl::ShaderCaseSpecification	spec;
213
214						spec.targetVersion	= version;
215						spec.expectResult	= glu::sl::EXPECT_PASS;
216						spec.caseType		= glu::sl::CASETYPE_VERTEX_ONLY;
217						spec.programs.resize(1);
218
219						spec.programs[0].sources << glu::VertexSource(mapped);
220
221						addOutputVar(&spec.values, outType, cases[caseNdx].output);
222
223						ret.push_back(new ShaderLibraryCase(testContext,
224															renderContext,
225															contextInfo,
226															(scalarCaseName + "_vertex").c_str(),
227															"",
228															spec));
229					}
230
231					if (testStage & SHADER_FRAGMENT)
232					{
233						glu::sl::ShaderCaseSpecification	spec;
234
235						spec.targetVersion	= version;
236						spec.expectResult	= glu::sl::EXPECT_PASS;
237						spec.caseType		= glu::sl::CASETYPE_FRAGMENT_ONLY;
238						spec.programs.resize(1);
239
240						spec.programs[0].sources << glu::FragmentSource(mapped);
241
242						addOutputVar(&spec.values, outType, cases[caseNdx].output);
243
244						ret.push_back(new ShaderLibraryCase(testContext,
245															renderContext,
246															contextInfo,
247															(scalarCaseName + "_fragment").c_str(),
248															"",
249															spec));
250					}
251				}
252			}
253		}
254	}
255
256	return ret;
257}
258
259} // ShaderConstExpr
260} // gls
261} // deqp
262