Home | History | Annotate | Download | only in glshared
      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>
     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.
     58 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 
     77 string ProgramLibrary::substitute (const std::string& templ) const
     78 {
     79 	return substitute(templ, map<string, string>());
     80 }
     81 
     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 
     88 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 
    136 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 
    178 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 
    247 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 
    416 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