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
30using tcu::Vec2;
31using tcu::Vec3;
32using tcu::Vec4;
33using tcu::Mat2;
34using tcu::Mat3;
35using tcu::Mat4;
36using de::toString;
37using std::map;
38using std::string;
39
40namespace deqp
41{
42namespace gls
43{
44namespace LongStressTestUtil
45{
46
47template <int Size>
48static 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.
58string 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
77string ProgramLibrary::substitute (const std::string& templ) const
78{
79	return substitute(templ, map<string, string>());
80}
81
82ProgramLibrary::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
88gls::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
136gls::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
178gls::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
247gls::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
416gls::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