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 
33 namespace deqp
34 {
35 namespace gls
36 {
37 namespace ShaderConstExpr
38 {
39 
addOutputVar(glu::sl::ValueBlock * dst,glu::DataType type,float output)40 static 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 
createTests(tcu::TestContext & testContext,glu::RenderContext & renderContext,const glu::ContextInfo & contextInfo,const TestParams * cases,int numCases,glu::GLSLVersion version,TestShaderStage testStage)75 std::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