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 
createTests(tcu::TestContext & testContext,glu::RenderContext & renderContext,const glu::ContextInfo & contextInfo,const TestParams * cases,int numCases,glu::GLSLVersion version,TestShaderStage testStage)40 std::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