1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 Utilities for tests with gls::LongStressCase.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsLongStressTestUtil.hpp"
25 #include "tcuStringTemplate.hpp"
26 #include "deStringUtil.hpp"
27 
28 #include "glw.h"
29 
30 using tcu::Vec2;
31 using tcu::Vec3;
32 using tcu::Vec4;
33 using tcu::Mat2;
34 using tcu::Mat3;
35 using tcu::Mat4;
36 using de::toString;
37 using std::map;
38 using std::string;
39 
40 namespace deqp
41 {
42 namespace gls
43 {
44 namespace LongStressTestUtil
45 {
46 
47 template <int Size>
translationMat(const float v)48 static tcu::Matrix<float, Size, Size> translationMat (const float v)
49 {
50 	tcu::Matrix<float, Size, Size>	res(1.0f);
51 	tcu::Vector<float, Size>		col(v);
52 	col[Size-1] = 1.0f;
53 	res.setColumn(Size-1, col);
54 	return res;
55 }
56 
57 // Specializes certain template patterns in templ for GLSL version m_glslVersion; params in additionalParams (optional) are also included in the substitution.
substitute(const string & templ,const map<string,string> & additionalParams) const58 string ProgramLibrary::substitute (const string& templ, const map<string, string>& additionalParams) const
59 {
60 	const bool				isGLSL3 = m_glslVersion == glu::GLSL_VERSION_300_ES;
61 	map<string, string>		params;
62 
63 	params["FRAG_HEADER"]		= isGLSL3 ? "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n" : "";
64 	params["VTX_HEADER"]		= isGLSL3 ? "#version 300 es\n"	: "";
65 	params["VTX_IN"]			= isGLSL3 ? "in"				: "attribute";
66 	params["VTX_OUT"]			= isGLSL3 ? "out"				: "varying";
67 	params["FRAG_IN"]			= isGLSL3 ? "in"				: "varying";
68 	params["FRAG_COLOR"]		= isGLSL3 ? "dEQP_FragColor"	: "gl_FragColor";
69 	params["TEXTURE_2D_FUNC"]	= isGLSL3 ? "texture"			: "texture2D";
70 	params["NS"]				= "${NS}"; // \note Keep these as-is, they're handled by StressCase.
71 
72 	params.insert(additionalParams.begin(), additionalParams.end());
73 
74 	return tcu::StringTemplate(templ.c_str()).specialize(params);
75 }
76 
substitute(const std::string & templ) const77 string ProgramLibrary::substitute (const std::string& templ) const
78 {
79 	return substitute(templ, map<string, string>());
80 }
81 
ProgramLibrary(const glu::GLSLVersion glslVersion)82 ProgramLibrary::ProgramLibrary (const glu::GLSLVersion glslVersion)
83 	: m_glslVersion (glslVersion)
84 {
85 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_100_ES || glslVersion == glu::GLSL_VERSION_300_ES);
86 }
87 
generateBufferContext(const int numDummyAttributes) const88 gls::ProgramContext ProgramLibrary::generateBufferContext (const int numDummyAttributes) const
89 {
90 	static const char* const vertexTemplate =
91 		"${VTX_HEADER}"
92 		"${VTX_IN} highp vec3 a_position;\n"
93 		"${VTX_DUMMY_INPUTS}"
94 		"${VTX_OUT} mediump vec4 v_color;\n"
95 		"\n"
96 		"void main (void)\n"
97 		"{\n"
98 		"	gl_Position = vec4(a_position, 1.0);\n"
99 		"	v_color = ${VTX_COLOR_EXPRESSION};\n"
100 		"}\n";
101 
102 	static const char* const fragmentTemplate =
103 		"${FRAG_HEADER}"
104 		"${FRAG_IN} mediump vec4 v_color;\n"
105 		"\n"
106 		"void main (void)\n"
107 		"{\n"
108 		"	${FRAG_COLOR} = v_color;\n"
109 		"}\n";
110 
111 	map<string, string> firstLevelParams;
112 
113 	{
114 		string vtxDummyInputs;
115 		string vtxColorExpr;
116 		for (int i = 0; i < numDummyAttributes; i++)
117 		{
118 			vtxDummyInputs	+= "${VTX_IN} mediump vec4 a_in" + toString(i) + ";\n";
119 			vtxColorExpr	+= string() + (i > 0 ? " + " : "") + "a_in" + toString(i);
120 		}
121 
122 		firstLevelParams["VTX_DUMMY_INPUTS"]		= substitute(vtxDummyInputs);
123 		firstLevelParams["VTX_COLOR_EXPRESSION"]	= vtxColorExpr;
124 	}
125 
126 	gls::ProgramContext context(substitute(vertexTemplate, firstLevelParams).c_str(), substitute(fragmentTemplate).c_str(), "a_position");
127 
128 	context.attributes.push_back(gls::VarSpec("a_position", Vec3(-0.1f), Vec3(0.1f)));
129 
130 	for (int i = 0; i < numDummyAttributes; i++)
131 		context.attributes.push_back(gls::VarSpec("a_in" + de::toString(i), Vec4(0.0f), Vec4(1.0f / (float)numDummyAttributes)));
132 
133 	return context;
134 }
135 
generateTextureContext(const int numTextures,const int texWid,const int texHei,const float positionFactor) const136 gls::ProgramContext ProgramLibrary::generateTextureContext (const int numTextures, const int texWid, const int texHei, const float positionFactor) const
137 {
138 	static const char* const vertexTemplate =
139 		"${VTX_HEADER}"
140 		"${VTX_IN} highp vec3 a_position;\n"
141 		"${VTX_IN} mediump vec2 a_texCoord;\n"
142 		"${VTX_OUT} mediump vec2 v_texCoord;\n"
143 		"uniform mediump mat4 u_posTrans;\n"
144 		"\n"
145 		"void main (void)\n"
146 		"{\n"
147 		"	gl_Position = u_posTrans * vec4(a_position, 1.0);\n"
148 		"	v_texCoord = a_texCoord;\n"
149 		"}\n";
150 
151 	static const char* const fragmentTemplate =
152 		"${FRAG_HEADER}"
153 		"${FRAG_IN} mediump vec2 v_texCoord;\n"
154 		"uniform mediump sampler2D u_sampler;\n"
155 		"\n"
156 		"void main (void)\n"
157 		"{\n"
158 		"	${FRAG_COLOR} = ${TEXTURE_2D_FUNC}(u_sampler, v_texCoord);\n"
159 		"}\n";
160 
161 	gls::ProgramContext context(substitute(vertexTemplate).c_str(), substitute(fragmentTemplate).c_str(), "a_position");
162 
163 	context.attributes.push_back(gls::VarSpec("a_position",		Vec3(-positionFactor),						Vec3(positionFactor)));
164 	context.attributes.push_back(gls::VarSpec("a_texCoord",		Vec2(0.0f),									Vec2(1.0f)));
165 
166 	context.uniforms.push_back(gls::VarSpec("u_sampler",		0));
167 	context.uniforms.push_back(gls::VarSpec("u_posTrans",		translationMat<4>(positionFactor-1.0f),		translationMat<4>(1.0f-positionFactor)));
168 
169 	for (int i = 0; i < numTextures; i++)
170 		context.textureSpecs.push_back(gls::TextureSpec(gls::TextureTestUtil::TEXTURETYPE_2D, 0,
171 														texWid, texHei, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, true,
172 														GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT,
173 														Vec4(0.0f), Vec4(1.0f)));
174 
175 	return context;
176 }
177 
generateBufferAndTextureContext(const int numTextures,const int texWid,const int texHei) const178 gls::ProgramContext ProgramLibrary::generateBufferAndTextureContext (const int numTextures, const int texWid, const int texHei) const
179 {
180 	static const char* const vertexTemplate =
181 		"${VTX_HEADER}"
182 		"${VTX_IN} highp vec3 a_position;\n"
183 		"${VTX_TEX_COORD_INPUTS}"
184 		"${VTX_TEX_COORD_OUTPUTS}"
185 		"\n"
186 		"void main (void)\n"
187 		"{\n"
188 		"	gl_Position = vec4(a_position, 1.0);\n"
189 		"${VTX_TEX_COORD_WRITES}"
190 		"}\n";
191 
192 	static const char* const fragmentTemplate =
193 		"${FRAG_HEADER}"
194 		"${FRAG_TEX_COORD_INPUTS}"
195 		"${FRAG_SAMPLERS}"
196 		"\n"
197 		"void main (void)\n"
198 		"{\n"
199 		"	${FRAG_COLOR} =${FRAG_COLOR_EXPRESSION};\n"
200 		"}\n";
201 
202 	map<string, string> firstLevelParams;
203 
204 	{
205 		string vtxTexCoordInputs;
206 		string vtxTexCoordOutputs;
207 		string vtxTexCoordWrites;
208 		string fragTexCoordInputs;
209 		string fragSamplers;
210 		string fragColorExpression;
211 
212 		for (int i = 0; i < numTextures; i++)
213 		{
214 			vtxTexCoordInputs		+= "${VTX_IN} mediump vec2 a_texCoord" + toString(i) + ";\n";
215 			vtxTexCoordOutputs		+= "${VTX_OUT} mediump vec2 v_texCoord" + toString(i) + ";\n";
216 			vtxTexCoordWrites		+= "\tv_texCoord" + toString(i) + " = " + "a_texCoord" + toString(i) + ";\n";
217 			fragTexCoordInputs		+= "${FRAG_IN} mediump vec2 v_texCoord" + toString(i) + ";\n";
218 			fragSamplers			+= "uniform mediump sampler2D u_sampler" + toString(i) + ";\n";
219 			fragColorExpression		+= string() + (i > 0 ? " +" : "") + "\n\t\t${TEXTURE_2D_FUNC}(u_sampler" + toString(i) + ", v_texCoord" + toString(i) + ")";
220 		}
221 
222 		firstLevelParams["VTX_TEX_COORD_INPUTS"]	= substitute(vtxTexCoordInputs);
223 		firstLevelParams["VTX_TEX_COORD_OUTPUTS"]	= substitute(vtxTexCoordOutputs);
224 		firstLevelParams["VTX_TEX_COORD_WRITES"]	= vtxTexCoordWrites;
225 		firstLevelParams["FRAG_TEX_COORD_INPUTS"]	= substitute(fragTexCoordInputs);
226 		firstLevelParams["FRAG_SAMPLERS"]			= fragSamplers;
227 		firstLevelParams["FRAG_COLOR_EXPRESSION"]	= substitute(fragColorExpression);
228 	}
229 
230 	gls::ProgramContext context(substitute(vertexTemplate, firstLevelParams).c_str(), substitute(fragmentTemplate, firstLevelParams).c_str(), "a_position");
231 
232 	context.attributes.push_back(gls::VarSpec("a_position", Vec3(-0.1f), Vec3(0.1f)));
233 
234 	for (int i = 0; i < numTextures; i++)
235 	{
236 		context.attributes.push_back(gls::VarSpec("a_texCoord" + de::toString(i), Vec2(0.0f), Vec2(1.0f)));
237 		context.uniforms.push_back(gls::VarSpec("u_sampler" + de::toString(i), i));
238 		context.textureSpecs.push_back(gls::TextureSpec(gls::TextureTestUtil::TEXTURETYPE_2D, i,
239 														texWid, texHei, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, true,
240 														GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT,
241 														Vec4(0.0f), Vec4(1.0f / (float)numTextures)));
242 	}
243 
244 	return context;
245 }
246 
generateFragmentPointLightContext(const int texWid,const int texHei) const247 gls::ProgramContext ProgramLibrary::generateFragmentPointLightContext (const int texWid, const int texHei) const
248 {
249 	static const char* const vertexTemplate =
250 		"${VTX_HEADER}"
251 		"struct Material\n"
252 		"{\n"
253 		"	mediump vec3	ambientColor;\n"
254 		"	mediump vec4	diffuseColor;\n"
255 		"	mediump vec3	emissiveColor;\n"
256 		"	mediump vec3	specularColor;\n"
257 		"	mediump float	shininess;\n"
258 		"};\n"
259 		"\n"
260 		"struct Light\n"
261 		"{\n"
262 		"	mediump vec3	color;\n"
263 		"	mediump vec4	position;\n"
264 		"	mediump vec3	direction;\n"
265 		"	mediump float	constantAttenuation;\n"
266 		"	mediump float	linearAttenuation;\n"
267 		"	mediump float	quadraticAttenuation;\n"
268 		"};\n"
269 		"\n"
270 		"${VTX_IN} highp vec4	a_position${NS};\n"
271 		"${VTX_IN} mediump vec3	a_normal${NS};\n"
272 		"${VTX_IN} mediump vec3	a_color${NS};\n"
273 		"${VTX_IN} mediump vec4	a_texCoord0${NS};\n"
274 		"\n"
275 		"uniform Material		u_material${NS};\n"
276 		"uniform Light			u_light${NS}[1];\n"
277 		"uniform highp mat4		u_mvpMatrix${NS};\n"
278 		"uniform mediump mat4	u_modelViewMatrix${NS};\n"
279 		"uniform mediump mat3	u_normalMatrix${NS};\n"
280 		"uniform mediump mat4	u_texCoordMatrix0${NS};\n"
281 		"\n"
282 		"${VTX_OUT} mediump vec4	v_baseColor${NS};\n"
283 		"${VTX_OUT} mediump vec2	v_texCoord0${NS};\n"
284 		"\n"
285 		"${VTX_OUT} mediump vec3	v_eyeNormal${NS};\n"
286 		"${VTX_OUT} mediump vec3	v_directionToLight${NS}[1];\n"
287 		"${VTX_OUT} mediump float	v_distanceToLight${NS}[1];\n"
288 		"\n"
289 		"vec3 direction (vec4 from, vec4 to)\n"
290 		"{\n"
291 		"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
292 		"}\n"
293 		"\n"
294 		"void main (void)\n"
295 		"{\n"
296 		"	gl_Position = u_mvpMatrix${NS} * a_position${NS};\n"
297 		"	v_texCoord0${NS} = (u_texCoordMatrix0${NS} * a_texCoord0${NS}).xy;\n"
298 		"\n"
299 		"	mediump vec4 eyePosition	= u_modelViewMatrix${NS} * a_position${NS};\n"
300 		"	mediump vec3 eyeNormal		= normalize(u_normalMatrix${NS} * a_normal${NS});\n"
301 		"\n"
302 		"	vec4 color	 = vec4(0.0, 0.0, 0.0, 1.0);\n"
303 		"	color.rgb	+= u_material${NS}.emissiveColor;\n"
304 		"\n"
305 		"	color.a		*= u_material${NS}.diffuseColor.a;\n"
306 		"\n"
307 		"	v_baseColor${NS} = color;\n"
308 		"\n"
309 		"	v_distanceToLight${NS}[0]	= distance(eyePosition, u_light${NS}[0].position);\n"
310 		"	v_directionToLight${NS}[0]	= normalize(direction(eyePosition, u_light${NS}[0].position));\n"
311 		"\n"
312 		"	v_eyeNormal${NS}			= eyeNormal;\n"
313 		"}\n";
314 
315 	static const char* const fragmentTemplate =
316 		"${FRAG_HEADER}"
317 		"struct Light\n"
318 		"{\n"
319 		"	mediump vec3	color;\n"
320 		"	mediump vec4	position;\n"
321 		"	mediump vec3	direction;\n"
322 		"	mediump float	constantAttenuation;\n"
323 		"	mediump float	linearAttenuation;\n"
324 		"	mediump float	quadraticAttenuation;\n"
325 		"};\n"
326 		"\n"
327 		"struct Material\n"
328 		"{\n"
329 		"	mediump vec3	ambientColor;\n"
330 		"	mediump vec4	diffuseColor;\n"
331 		"	mediump vec3	emissiveColor;\n"
332 		"	mediump vec3	specularColor;\n"
333 		"	mediump float	shininess;\n"
334 		"};\n"
335 		"\n"
336 		"uniform sampler2D		u_sampler0${NS};\n"
337 		"uniform Light			u_light${NS}[1];\n"
338 		"uniform Material		u_material${NS};\n"
339 		"\n"
340 		"${FRAG_IN} mediump vec4	v_baseColor${NS};\n"
341 		"${FRAG_IN} mediump vec2	v_texCoord0${NS};\n"
342 		"\n"
343 		"${FRAG_IN} mediump vec3	v_eyeNormal${NS};\n"
344 		"${FRAG_IN} mediump vec3	v_directionToLight${NS}[1];\n"
345 		"${FRAG_IN} mediump float	v_distanceToLight${NS}[1];\n"
346 		"\n"
347 		"mediump vec3 computeLighting (Light light, mediump vec3 directionToLight, mediump vec3 vertexEyeNormal)\n"
348 		"{\n"
349 		"	mediump float	normalDotDirection	= max(dot(vertexEyeNormal, directionToLight), 0.0);\n"
350 		"	mediump	vec3	color				= normalDotDirection * u_material${NS}.diffuseColor.rgb * light.color;\n"
351 		"\n"
352 		"	if (normalDotDirection != 0.0)\n"
353 		"	{\n"
354 		"		mediump vec3 h = normalize(directionToLight + vec3(0.0, 0.0, 1.0));\n"
355 		"		color.rgb += pow(max(dot(vertexEyeNormal, h), 0.0), u_material${NS}.shininess) * u_material${NS}.specularColor * light.color;\n"
356 		"	}\n"
357 		"\n"
358 		"	return color;\n"
359 		"}\n"
360 		"\n"
361 		"mediump float computePointLightAttenuation (Light light, mediump float distanceToLight)\n"
362 		"{\n"
363 		"	mediump float	constantAttenuation		= light.constantAttenuation;\n"
364 		"	mediump float	linearAttenuation		= light.linearAttenuation * distanceToLight;\n"
365 		"	mediump float	quadraticAttenuation	= light.quadraticAttenuation * distanceToLight * distanceToLight;\n"
366 		"\n"
367 		"	return 1.0 / (constantAttenuation + linearAttenuation + quadraticAttenuation);\n"
368 		"}\n"
369 		"\n"
370 		"void main (void)\n"
371 		"{\n"
372 		"	mediump vec3 eyeNormal	= normalize(v_eyeNormal${NS});\n"
373 		"	mediump vec4 color		= v_baseColor${NS};\n"
374 		"\n"
375 		"	color.rgb += computePointLightAttenuation(u_light${NS}[0], v_distanceToLight${NS}[0]) * computeLighting(u_light${NS}[0], normalize(v_directionToLight${NS}[0]), eyeNormal);\n"
376 		"\n"
377 		"	color *= ${TEXTURE_2D_FUNC}(u_sampler0${NS}, v_texCoord0${NS});\n"
378 		"\n"
379 		"	${FRAG_COLOR} = color;\n"
380 		"}\n";
381 
382 	gls::ProgramContext context(substitute(vertexTemplate).c_str(), substitute(fragmentTemplate).c_str(), "a_position${NS}");
383 
384 	context.attributes.push_back(gls::VarSpec("a_position${NS}",						Vec4(-1.0f),				Vec4(1.0f)));
385 	context.attributes.push_back(gls::VarSpec("a_normal${NS}",							Vec3(-1.0f),				Vec3(1.0f)));
386 	context.attributes.push_back(gls::VarSpec("a_texCoord0${NS}",						Vec4(-1.0f),				Vec4(1.0f)));
387 
388 	context.uniforms.push_back(gls::VarSpec("u_material${NS}.ambientColor",				Vec3(0.0f),					Vec3(1.0f)));
389 	context.uniforms.push_back(gls::VarSpec("u_material${NS}.diffuseColor",				Vec4(0.0f),					Vec4(1.0f)));
390 	context.uniforms.push_back(gls::VarSpec("u_material${NS}.emissiveColor",			Vec3(0.0f),					Vec3(1.0f)));
391 	context.uniforms.push_back(gls::VarSpec("u_material${NS}.specularColor",			Vec3(0.0f),					Vec3(1.0f)));
392 	context.uniforms.push_back(gls::VarSpec("u_material${NS}.shininess",				0.0f,						1.0f));
393 
394 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].color",					Vec3(0.0f),					Vec3(1.0f)));
395 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].position",					Vec4(-1.0f),				Vec4(1.0f)));
396 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].direction",				Vec3(-1.0f),				Vec3(1.0f)));
397 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].constantAttenuation",		0.1f,						1.0f));
398 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].linearAttenuation",		0.1f,						1.0f));
399 	context.uniforms.push_back(gls::VarSpec("u_light${NS}[0].quadraticAttenuation",		0.1f,						1.0f));
400 
401 	context.uniforms.push_back(gls::VarSpec("u_mvpMatrix${NS}",							translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
402 	context.uniforms.push_back(gls::VarSpec("u_modelViewMatrix${NS}",					translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
403 	context.uniforms.push_back(gls::VarSpec("u_normalMatrix${NS}",						translationMat<3>(-0.2f),	translationMat<3>(0.2f)));
404 	context.uniforms.push_back(gls::VarSpec("u_texCoordMatrix0${NS}",					translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
405 
406 	context.uniforms.push_back(gls::VarSpec("u_sampler0${NS}", 0));
407 
408 	context.textureSpecs.push_back(gls::TextureSpec(gls::TextureTestUtil::TEXTURETYPE_2D, 0,
409 													texWid, texHei, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA,
410 													true, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT,
411 													Vec4(0.0f), Vec4(1.0f)));
412 
413 	return context;
414 }
415 
generateVertexUniformLoopLightContext(const int texWid,const int texHei) const416 gls::ProgramContext ProgramLibrary::generateVertexUniformLoopLightContext (const int texWid, const int texHei) const
417 {
418 	static const char* const vertexTemplate =
419 		"${VTX_HEADER}"
420 		"struct Material {\n"
421 		"	mediump vec3 ambientColor;\n"
422 		"	mediump vec4 diffuseColor;\n"
423 		"	mediump vec3 emissiveColor;\n"
424 		"	mediump vec3 specularColor;\n"
425 		"	mediump float shininess;\n"
426 		"};\n"
427 		"struct Light {\n"
428 		"	mediump vec3 color;\n"
429 		"	mediump vec4 position;\n"
430 		"	mediump vec3 direction;\n"
431 		"	mediump float constantAttenuation;\n"
432 		"	mediump float linearAttenuation;\n"
433 		"	mediump float quadraticAttenuation;\n"
434 		"	mediump float spotExponent;\n"
435 		"	mediump float spotCutoff;\n"
436 		"};\n"
437 		"${VTX_IN} highp vec4 a_position${NS};\n"
438 		"${VTX_IN} mediump vec3 a_normal${NS};\n"
439 		"${VTX_IN} mediump vec4 a_texCoord0${NS};\n"
440 		"uniform Material u_material${NS};\n"
441 		"uniform Light u_directionalLight${NS}[1];\n"
442 		"uniform mediump int u_directionalLightCount${NS};\n"
443 		"uniform Light u_spotLight${NS}[4];\n"
444 		"uniform mediump int u_spotLightCount${NS};\n"
445 		"uniform highp mat4 u_mvpMatrix${NS};\n"
446 		"uniform highp mat4 u_modelViewMatrix${NS};\n"
447 		"uniform mediump mat3 u_normalMatrix${NS};\n"
448 		"uniform mediump mat4 u_texCoordMatrix0${NS};\n"
449 		"${VTX_OUT} mediump vec4 v_color${NS};\n"
450 		"${VTX_OUT} mediump vec2 v_texCoord0${NS};\n"
451 		"mediump vec3 direction (mediump vec4 from, mediump vec4 to)\n"
452 		"{\n"
453 		"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
454 		"}\n"
455 		"\n"
456 		"mediump vec3 computeLighting (\n"
457 		"	mediump vec3 directionToLight,\n"
458 		"	mediump vec3 halfVector,\n"
459 		"	mediump vec3 normal,\n"
460 		"	mediump vec3 lightColor,\n"
461 		"	mediump vec3 diffuseColor,\n"
462 		"	mediump vec3 specularColor,\n"
463 		"	mediump float shininess)\n"
464 		"{\n"
465 		"	mediump float normalDotDirection  = max(dot(normal, directionToLight), 0.0);\n"
466 		"	mediump vec3  color               = normalDotDirection * diffuseColor * lightColor;\n"
467 		"\n"
468 		"	if (normalDotDirection != 0.0)\n"
469 		"		color += pow(max(dot(normal, halfVector), 0.0), shininess) * specularColor * lightColor;\n"
470 		"\n"
471 		"	return color;\n"
472 		"}\n"
473 		"\n"
474 		"mediump float computeDistanceAttenuation (mediump float distToLight, mediump float constAtt, mediump float linearAtt, mediump float quadraticAtt)\n"
475 		"{\n"
476 		"	return 1.0 / (constAtt + linearAtt * distToLight + quadraticAtt * distToLight * distToLight);\n"
477 		"}\n"
478 		"\n"
479 		"mediump float computeSpotAttenuation (\n"
480 		"	mediump vec3  directionToLight,\n"
481 		"	mediump vec3  lightDir,\n"
482 		"	mediump float spotExponent,\n"
483 		"	mediump float spotCutoff)\n"
484 		"{\n"
485 		"	mediump float spotEffect = dot(lightDir, normalize(-directionToLight));\n"
486 		"\n"
487 		"	if (spotEffect < spotCutoff)\n"
488 		"		spotEffect = 0.0;\n"
489 		"\n"
490 		"	spotEffect = pow(spotEffect, spotExponent);\n"
491 		"	return spotEffect;\n"
492 		"}\n"
493 		"\n"
494 		"void main (void)\n"
495 		"{\n"
496 		"	highp vec4 position = a_position${NS};\n"
497 		"	highp vec3 normal = a_normal${NS};\n"
498 		"	gl_Position = u_mvpMatrix${NS} * position;\n"
499 		"	v_texCoord0${NS} = (u_texCoordMatrix0${NS} * a_texCoord0${NS}).xy;\n"
500 		"	mediump vec4 color = vec4(u_material${NS}.emissiveColor, u_material${NS}.diffuseColor.a);\n"
501 		"\n"
502 		"	highp vec4 eyePosition = u_modelViewMatrix${NS} * position;\n"
503 		"	mediump vec3 eyeNormal = normalize(u_normalMatrix${NS} * normal);\n"
504 		"	for (int i = 0; i < u_directionalLightCount${NS}; i++)\n"
505 		"	{\n"
506 		"		mediump vec3 directionToLight = -u_directionalLight${NS}[i].direction;\n"
507 		"		mediump vec3 halfVector = normalize(directionToLight + vec3(0.0, 0.0, 1.0));\n"
508 		"		color.rgb += computeLighting(directionToLight, halfVector, eyeNormal, u_directionalLight${NS}[i].color, u_material${NS}.diffuseColor.rgb, u_material${NS}.specularColor, u_material${NS}.shininess);\n"
509 		"	}\n"
510 		"\n"
511 		"	for (int i = 0; i < u_spotLightCount${NS}; i++)\n"
512 		"	{\n"
513 		"		mediump float distanceToLight = distance(eyePosition, u_spotLight${NS}[i].position);\n"
514 		"		mediump vec3 directionToLight = normalize(direction(eyePosition, u_spotLight${NS}[i].position));\n"
515 		"		mediump vec3 halfVector = normalize(directionToLight + vec3(0.0, 0.0, 1.0));\n"
516 		"		color.rgb += computeLighting(directionToLight, halfVector, eyeNormal, u_spotLight${NS}[i].color, u_material${NS}.diffuseColor.rgb, u_material${NS}.specularColor, u_material${NS}.shininess) * computeDistanceAttenuation(distanceToLight, u_spotLight${NS}[i].constantAttenuation, u_spotLight${NS}[i].linearAttenuation, u_spotLight${NS}[i].quadraticAttenuation) * computeSpotAttenuation(directionToLight, u_spotLight${NS}[i].direction, u_spotLight${NS}[i].spotExponent, u_spotLight${NS}[i].spotCutoff);\n"
517 		"	}\n"
518 		"\n"
519 		"\n"
520 		"	v_color${NS} = color;\n"
521 		"}\n";
522 
523 	static const char* const fragmentTemplate =
524 		"${FRAG_HEADER}"
525 		"uniform sampler2D u_sampler0${NS};\n"
526 		"${FRAG_IN} mediump vec4 v_color${NS};\n"
527 		"${FRAG_IN} mediump vec2 v_texCoord0${NS};\n"
528 		"void main (void)\n"
529 		"{\n"
530 		"	mediump vec2 texCoord0 = v_texCoord0${NS};\n"
531 		"	mediump vec4 color = v_color${NS};\n"
532 		"	color *= ${TEXTURE_2D_FUNC}(u_sampler0${NS}, texCoord0);\n"
533 		"	${FRAG_COLOR} = color;\n"
534 		"}\n";
535 
536 	gls::ProgramContext context(substitute(vertexTemplate).c_str(), substitute(fragmentTemplate).c_str(), "a_position${NS}");
537 
538 	context.attributes.push_back	(gls::VarSpec("a_position${NS}",									Vec4(-1.0f),				Vec4(1.0f)));
539 	context.attributes.push_back	(gls::VarSpec("a_normal${NS}",										Vec3(-1.0f),				Vec3(1.0f)));
540 	context.attributes.push_back	(gls::VarSpec("a_texCoord0${NS}",									Vec4(-1.0f),				Vec4(1.0f)));
541 
542 	context.uniforms.push_back		(gls::VarSpec("u_material${NS}.ambientColor",						Vec3(0.0f),					Vec3(1.0f)));
543 	context.uniforms.push_back		(gls::VarSpec("u_material${NS}.diffuseColor",						Vec4(0.0f),					Vec4(1.0f)));
544 	context.uniforms.push_back		(gls::VarSpec("u_material${NS}.emissiveColor",						Vec3(0.0f),					Vec3(1.0f)));
545 	context.uniforms.push_back		(gls::VarSpec("u_material${NS}.specularColor",						Vec3(0.0f),					Vec3(1.0f)));
546 	context.uniforms.push_back		(gls::VarSpec("u_material${NS}.shininess",							0.0f,						1.0f));
547 
548 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].color",					Vec3(0.0f),					Vec3(1.0f)));
549 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].position",				Vec4(-1.0f),				Vec4(1.0f)));
550 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].direction",				Vec3(-1.0f),				Vec3(1.0f)));
551 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].constantAttenuation",		0.1f,						1.0f));
552 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].linearAttenuation",		0.1f,						1.0f));
553 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].quadraticAttenuation",	0.1f,						1.0f));
554 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].spotExponent",			0.1f,						1.0f));
555 	context.uniforms.push_back		(gls::VarSpec("u_directionalLight${NS}[0].spotCutoff",				0.1f,						1.0f));
556 
557 	context.uniforms.push_back		(gls::VarSpec("u_directionalLightCount${NS}",						1));
558 
559 	for (int i = 0; i < 4; i++)
560 	{
561 		const std::string ndxStr = de::toString(i);
562 
563 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].color",					Vec3(0.0f),					Vec3(1.0f)));
564 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].position",				Vec4(-1.0f),				Vec4(1.0f)));
565 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].direction",				Vec3(-1.0f),				Vec3(1.0f)));
566 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].constantAttenuation",		0.1f,						1.0f));
567 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].linearAttenuation",		0.1f,						1.0f));
568 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].quadraticAttenuation",	0.1f,						1.0f));
569 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].spotExponent",			0.1f,						1.0f));
570 		context.uniforms.push_back(gls::VarSpec("u_spotLight${NS}["+ndxStr+"].spotCutoff",				0.1f,						1.0f));
571 	}
572 
573 	context.uniforms.push_back		(gls::VarSpec("u_spotLightCount${NS}",								4));
574 
575 	context.uniforms.push_back		(gls::VarSpec("u_mvpMatrix${NS}",									translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
576 	context.uniforms.push_back		(gls::VarSpec("u_modelViewMatrix${NS}",								translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
577 	context.uniforms.push_back		(gls::VarSpec("u_normalMatrix${NS}",								translationMat<3>(-0.2f),	translationMat<3>(0.2f)));
578 	context.uniforms.push_back		(gls::VarSpec("u_texCoordMatrix0${NS}",								translationMat<4>(-0.2f),	translationMat<4>(0.2f)));
579 
580 	context.uniforms.push_back		(gls::VarSpec("u_sampler0${NS}",									0));
581 
582 	context.textureSpecs.push_back	(gls::TextureSpec(gls::TextureTestUtil::TEXTURETYPE_2D, 0,
583 													  texWid, texHei, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA,
584 													  true, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT,
585 													  Vec4(0.0f), Vec4(1.0f)));
586 
587 	return context;
588 }
589 
590 } // StressTestUtil
591 } // gls
592 } // deqp
593