1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 FBO test utilities.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFboTestUtil.hpp"
25#include "sglrContextUtil.hpp"
26#include "sglrGLContext.hpp"
27#include "sglrReferenceContext.hpp"
28#include "gluTextureUtil.hpp"
29#include "tcuTextureUtil.hpp"
30#include "deStringUtil.hpp"
31#include "deMath.h"
32#include "glwEnums.hpp"
33#include "glwFunctions.hpp"
34
35#include <limits>
36
37namespace deqp
38{
39namespace gles3
40{
41namespace Functional
42{
43namespace FboTestUtil
44{
45
46using std::string;
47using std::vector;
48using tcu::Vec2;
49using tcu::Vec3;
50using tcu::Vec4;
51using tcu::IVec2;
52using tcu::IVec3;
53using tcu::IVec4;
54
55static rr::GenericVecType mapDataTypeToGenericVecType(glu::DataType type)
56{
57	switch (type)
58	{
59		case glu::TYPE_FLOAT_VEC4:	return rr::GENERICVECTYPE_FLOAT;
60		case glu::TYPE_INT_VEC4:	return rr::GENERICVECTYPE_INT32;
61		case glu::TYPE_UINT_VEC4:	return rr::GENERICVECTYPE_UINT32;
62		default:
63			DE_ASSERT(DE_FALSE);
64			return rr::GENERICVECTYPE_LAST;
65	}
66}
67
68template <typename T>
69static tcu::Vector<T, 4> castVectorSaturate (const tcu::Vec4& in)
70{
71	return tcu::Vector<T, 4>(((double)in.x() + 0.5 >= (double)std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : (((double)in.x() - 0.5 <= (double)std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.x()))),
72	                         ((double)in.y() + 0.5 >= (double)std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : (((double)in.y() - 0.5 <= (double)std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.y()))),
73							 ((double)in.z() + 0.5 >= (double)std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : (((double)in.z() - 0.5 <= (double)std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.z()))),
74							 ((double)in.w() + 0.5 >= (double)std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : (((double)in.w() - 0.5 <= (double)std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.w()))));
75}
76
77FlatColorShader::FlatColorShader (glu::DataType outputType)
78	: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
79					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
80					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
81					<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
82					<< sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
83					<< sglr::pdec::VertexSource(
84							"#version 300 es\n"
85							"in highp vec4 a_position;\n"
86							"void main (void)\n"
87							"{\n"
88							"	gl_Position = a_position;\n"
89							"}\n")
90					<< sglr::pdec::FragmentSource(
91							string(
92								"#version 300 es\n"
93								"uniform highp vec4 u_color;\n"
94								"layout(location = 0) out highp ") + glu::getDataTypeName(outputType) + " o_color;\n"
95								"void main (void)\n"
96								"{\n"
97								"	o_color = " + glu::getDataTypeName(outputType) + "(u_color);\n"
98								"}\n"))
99	, m_outputType(outputType)
100{
101}
102
103void FlatColorShader::setColor (sglr::Context& context, deUint32 program, const tcu::Vec4& color)
104{
105	deInt32 location = context.getUniformLocation(program, "u_color");
106
107	context.useProgram(program);
108	context.uniform4fv(location, 1, color.getPtr());
109}
110
111void FlatColorShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
112{
113	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
114	{
115		rr::VertexPacket& packet = *packets[packetNdx];
116
117		packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
118	}
119}
120
121void FlatColorShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
122{
123	const tcu::Vec4		color	(m_uniforms[0].value.f4);
124	const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
125	const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
126
127	DE_UNREF(packets);
128
129	if (m_outputType == glu::TYPE_FLOAT_VEC4)
130	{
131		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
132		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
133			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
134	}
135	else if (m_outputType == glu::TYPE_INT_VEC4)
136	{
137		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
138		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
139			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
140	}
141	else if (m_outputType == glu::TYPE_UINT_VEC4)
142	{
143		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
144		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
145			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
146	}
147	else
148		DE_ASSERT(DE_FALSE);
149}
150
151GradientShader::GradientShader (glu::DataType outputType)
152	: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
153					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
154					<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
155					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
156					<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
157					<< sglr::pdec::Uniform("u_gradientMin", glu::TYPE_FLOAT_VEC4)
158					<< sglr::pdec::Uniform("u_gradientMax", glu::TYPE_FLOAT_VEC4)
159					<< sglr::pdec::VertexSource(
160							"#version 300 es\n"
161							"in highp vec4 a_position;\n"
162							"in highp vec4 a_coord;\n"
163							"out highp vec4 v_coord;\n"
164							"void main (void)\n"
165							"{\n"
166							"	gl_Position = a_position;\n"
167							"	v_coord = a_coord;\n"
168							"}\n")
169					<< sglr::pdec::FragmentSource(
170							string(
171								"#version 300 es\n"
172								"in highp vec4 v_coord;\n"
173								"uniform highp vec4 u_gradientMin;\n"
174								"uniform highp vec4 u_gradientMax;\n"
175								"layout(location = 0) out highp ") + glu::getDataTypeName(outputType) + " o_color;\n"
176								"void main (void)\n"
177								"{\n"
178								"	highp float x = v_coord.x;\n"
179								"	highp float y = v_coord.y;\n"
180								"	highp float f0 = (x + y) * 0.5;\n"
181								"	highp float f1 = 0.5 + (x - y) * 0.5;\n"
182								"	highp vec4 fv = vec4(f0, f1, 1.0f-f0, 1.0f-f1);\n"
183								"	o_color = " + glu::getDataTypeName(outputType) + "(u_gradientMin + (u_gradientMax-u_gradientMin)*fv);\n"
184								"}\n"))
185	, m_outputType(outputType)
186{
187}
188
189void GradientShader::setGradient (sglr::Context& ctx, deUint32 program, const tcu::Vec4& gradientMin, const tcu::Vec4& gradientMax)
190{
191	ctx.useProgram(program);
192	ctx.uniform4fv(ctx.getUniformLocation(program, "u_gradientMin"), 1, gradientMin.getPtr());
193	ctx.uniform4fv(ctx.getUniformLocation(program, "u_gradientMax"), 1, gradientMax.getPtr());
194}
195
196void GradientShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
197{
198	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
199	{
200		rr::VertexPacket& packet = *packets[packetNdx];
201
202		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
203		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
204	}
205}
206
207void GradientShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
208{
209	const tcu::Vec4	gradientMin(m_uniforms[0].value.f4);
210	const tcu::Vec4	gradientMax(m_uniforms[1].value.f4);
211
212	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
213	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
214	{
215		const tcu::Vec4		coord	= rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
216		const float			x		= coord.x();
217		const float			y		= coord.y();
218		const float			f0		= (x + y) * 0.5f;
219		const float			f1		= 0.5f + (x - y) * 0.5f;
220		const tcu::Vec4		fv		= Vec4(f0, f1, 1.0f-f0, 1.0f-f1);
221
222		const tcu::Vec4		color	= gradientMin + (gradientMax-gradientMin) * fv;
223		const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
224		const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
225
226		if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
227		else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
228		else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
229		else
230			DE_ASSERT(DE_FALSE);
231	}
232}
233
234static string genTexFragmentShader (const vector<glu::DataType>& samplerTypes, glu::DataType outputType)
235{
236	const char*			precision	= "highp";
237	std::ostringstream	src;
238
239	src << "#version 300 es\n"
240		<< "layout(location = 0) out highp " << glu::getDataTypeName(outputType) << " o_color0;\n";
241
242	src << "in highp vec2 v_coord;\n";
243
244	for (int samplerNdx = 0; samplerNdx < (int)samplerTypes.size(); samplerNdx++)
245	{
246		src << "uniform " << precision << " " << glu::getDataTypeName(samplerTypes[samplerNdx]) << " u_sampler" << samplerNdx << ";\n";
247		src << "uniform " << precision << " vec4 u_texScale" << samplerNdx << ";\n";
248		src << "uniform " << precision << " vec4 u_texBias" << samplerNdx << ";\n";
249	}
250
251	// Output scale & bias
252	src << "uniform " << precision << " vec4 u_outScale0;\n"
253		<< "uniform " << precision << " vec4 u_outBias0;\n";
254
255	src << "\n"
256		<< "void main (void)\n"
257		<< "{\n"
258		<< "	" << precision << " vec4 out0 = vec4(0.0);\n";
259
260	// Texture input fetch and combine.
261	for (int inNdx = 0; inNdx < (int)samplerTypes.size(); inNdx++)
262		src << "\tout0 += vec4("
263			<< "texture(u_sampler" << inNdx << ", v_coord)) * u_texScale" << inNdx << " + u_texBias" << inNdx << ";\n";
264
265	// Write output.
266	src << "	o_color0 = " << glu::getDataTypeName(outputType) << "(out0 * u_outScale0 + u_outBias0);\n";
267
268	src << "}\n";
269
270	return src.str();
271}
272
273static sglr::pdec::ShaderProgramDeclaration genTexture2DShaderDecl (const DataTypes& samplerTypes, glu::DataType outputType)
274{
275	sglr::pdec::ShaderProgramDeclaration decl;
276
277	decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT);
278	decl << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT);
279	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
280	decl << sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType));
281
282	decl << sglr::pdec::VertexSource(
283		"#version 300 es\n"
284		"in highp vec4 a_position;\n"
285		"in highp vec2 a_coord;\n"
286		"out highp vec2 v_coord;\n"
287		"void main(void)\n"
288		"{\n"
289		"	gl_Position = a_position;\n"
290		"	v_coord = a_coord;\n"
291		"}\n");
292	decl << sglr::pdec::FragmentSource(genTexFragmentShader(samplerTypes.vec, outputType));
293
294	decl << sglr::pdec::Uniform("u_outScale0", glu::TYPE_FLOAT_VEC4);
295	decl << sglr::pdec::Uniform("u_outBias0", glu::TYPE_FLOAT_VEC4);
296
297	for (size_t ndx = 0; ndx < samplerTypes.vec.size(); ++ndx)
298	{
299		decl << sglr::pdec::Uniform(std::string("u_sampler")  + de::toString(ndx), samplerTypes.vec[ndx]);
300		decl << sglr::pdec::Uniform(std::string("u_texScale") + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
301		decl << sglr::pdec::Uniform(std::string("u_texBias")  + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
302	}
303
304	return decl;
305}
306
307Texture2DShader::Texture2DShader (const DataTypes& samplerTypes, glu::DataType outputType, const Vec4& outScale, const Vec4& outBias)
308	: sglr::ShaderProgram	(genTexture2DShaderDecl(samplerTypes, outputType))
309	, m_outScale			(outScale)
310	, m_outBias				(outBias)
311	, m_outputType			(outputType)
312{
313	m_inputs.resize(samplerTypes.vec.size());
314
315	// Initialize units.
316	for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
317	{
318		m_inputs[ndx].unitNdx	= ndx;
319		m_inputs[ndx].scale		= Vec4(1.0f);
320		m_inputs[ndx].bias		= Vec4(0.0f);
321	}
322}
323
324void Texture2DShader::setUnit (int inputNdx, int unitNdx)
325{
326	m_inputs[inputNdx].unitNdx = unitNdx;
327}
328
329void Texture2DShader::setTexScaleBias (int inputNdx, const Vec4& scale, const Vec4& bias)
330{
331	m_inputs[inputNdx].scale	= scale;
332	m_inputs[inputNdx].bias		= bias;
333}
334
335void Texture2DShader::setOutScaleBias (const Vec4& scale, const Vec4& bias)
336{
337	m_outScale	= scale;
338	m_outBias	= bias;
339}
340
341void Texture2DShader::setUniforms (sglr::Context& gl, deUint32 program) const
342{
343	gl.useProgram(program);
344
345	for (int texNdx = 0; texNdx < (int)m_inputs.size(); texNdx++)
346	{
347		string	samplerName	= string("u_sampler") + de::toString(texNdx);
348		string	scaleName	= string("u_texScale") + de::toString(texNdx);
349		string	biasName	= string("u_texBias") + de::toString(texNdx);
350
351		gl.uniform1i(gl.getUniformLocation(program, samplerName.c_str()), m_inputs[texNdx].unitNdx);
352		gl.uniform4fv(gl.getUniformLocation(program, scaleName.c_str()), 1, m_inputs[texNdx].scale.getPtr());
353		gl.uniform4fv(gl.getUniformLocation(program, biasName.c_str()), 1, m_inputs[texNdx].bias.getPtr());
354	}
355
356	gl.uniform4fv(gl.getUniformLocation(program, "u_outScale0"), 1, m_outScale.getPtr());
357	gl.uniform4fv(gl.getUniformLocation(program, "u_outBias0"), 1, m_outBias.getPtr());
358}
359
360void Texture2DShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
361{
362	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
363	{
364		rr::VertexPacket& packet = *packets[packetNdx];
365
366		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
367		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
368	}
369}
370
371void Texture2DShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
372{
373	const tcu::Vec4 outScale (m_uniforms[0].value.f4);
374	const tcu::Vec4 outBias	 (m_uniforms[1].value.f4);
375
376	tcu::Vec2 texCoords[4];
377	tcu::Vec4 colors[4];
378
379	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
380	{
381		// setup tex coords
382		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
383		{
384			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
385			texCoords[fragNdx] = tcu::Vec2(coord.x(), coord.y());
386		}
387
388		// clear result
389		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
390			colors[fragNdx] = tcu::Vec4(0.0f);
391
392		// sample each texture
393		for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
394		{
395			const sglr::rc::Texture2D*	tex		= m_uniforms[2 + ndx*3].sampler.tex2D;
396			const tcu::Vec4				scale	(m_uniforms[2 + ndx*3 + 1].value.f4);
397			const tcu::Vec4				bias	(m_uniforms[2 + ndx*3 + 2].value.f4);
398			tcu::Vec4 tmpColors[4];
399
400			tex->sample4(tmpColors, texCoords);
401
402			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
403				colors[fragNdx] += tmpColors[fragNdx] * scale + bias;
404		}
405
406		// write out
407		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
408		{
409			const tcu::Vec4		color	= colors[fragNdx] * outScale + outBias;
410			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
411			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
412
413			if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
414			else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
415			else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
416			else
417				DE_ASSERT(DE_FALSE);
418		}
419	}
420}
421
422TextureCubeShader::TextureCubeShader (glu::DataType samplerType, glu::DataType outputType)
423	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
424							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
425							<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
426							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
427							<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
428							<< sglr::pdec::Uniform("u_coordMat", glu::TYPE_FLOAT_MAT3)
429							<< sglr::pdec::Uniform("u_sampler0", samplerType)
430							<< sglr::pdec::Uniform("u_scale", glu::TYPE_FLOAT_VEC4)
431							<< sglr::pdec::Uniform("u_bias", glu::TYPE_FLOAT_VEC4)
432							<< sglr::pdec::VertexSource(
433									"#version 300 es\n"
434									"in highp vec4 a_position;\n"
435									"in mediump vec2 a_coord;\n"
436									"uniform mat3 u_coordMat;\n"
437									"out mediump vec3 v_coord;\n"
438									"void main (void)\n"
439									"{\n"
440									"	gl_Position = a_position;\n"
441									"	v_coord = u_coordMat * vec3(a_coord, 1.0);\n"
442									"}\n")
443							<< sglr::pdec::FragmentSource(
444									string("") +
445									"#version 300 es\n"
446									"uniform highp " + glu::getDataTypeName(samplerType) + " u_sampler0;\n"
447									"uniform highp vec4 u_scale;\n"
448									"uniform highp vec4 u_bias;\n"
449									"in mediump vec3 v_coord;\n"
450									"layout(location = 0) out highp " + glu::getDataTypeName(outputType) + " o_color;\n"
451									"void main (void)\n"
452									"{\n"
453									"	o_color = " + glu::getDataTypeName(outputType) + "(vec4(texture(u_sampler0, v_coord)) * u_scale + u_bias);\n"
454									"}\n"))
455	, m_texScale	(1.0f)
456	, m_texBias		(0.0f)
457	, m_outputType	(outputType)
458{
459}
460
461void TextureCubeShader::setFace (tcu::CubeFace face)
462{
463	static const float s_cubeTransforms[][3*3] =
464	{
465		// Face -X: (x, y, 1) -> (-1, -(2*y-1), +(2*x-1))
466		{  0.0f,  0.0f, -1.0f,
467		   0.0f, -2.0f,  1.0f,
468		   2.0f,  0.0f, -1.0f },
469		// Face +X: (x, y, 1) -> (+1, -(2*y-1), -(2*x-1))
470		{  0.0f,  0.0f,  1.0f,
471		   0.0f, -2.0f,  1.0f,
472		  -2.0f,  0.0f,  1.0f },
473		// Face -Y: (x, y, 1) -> (+(2*x-1), -1, -(2*y-1))
474		{  2.0f,  0.0f, -1.0f,
475		   0.0f,  0.0f, -1.0f,
476		   0.0f, -2.0f,  1.0f },
477		// Face +Y: (x, y, 1) -> (+(2*x-1), +1, +(2*y-1))
478		{  2.0f,  0.0f, -1.0f,
479		   0.0f,  0.0f,  1.0f,
480		   0.0f,  2.0f, -1.0f },
481		// Face -Z: (x, y, 1) -> (-(2*x-1), -(2*y-1), -1)
482		{ -2.0f,  0.0f,  1.0f,
483		   0.0f, -2.0f,  1.0f,
484		   0.0f,  0.0f, -1.0f },
485		// Face +Z: (x, y, 1) -> (+(2*x-1), -(2*y-1), +1)
486		{  2.0f,  0.0f, -1.0f,
487		   0.0f, -2.0f,  1.0f,
488		   0.0f,  0.0f,  1.0f }
489	};
490	DE_ASSERT(de::inBounds<int>(face, 0, tcu::CUBEFACE_LAST));
491	m_coordMat = tcu::Mat3(s_cubeTransforms[face]);
492}
493
494void TextureCubeShader::setTexScaleBias (const Vec4& scale, const Vec4& bias)
495{
496	m_texScale	= scale;
497	m_texBias	= bias;
498}
499
500void TextureCubeShader::setUniforms (sglr::Context& gl, deUint32 program) const
501{
502	gl.useProgram(program);
503
504	gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), 0);
505	gl.uniformMatrix3fv(gl.getUniformLocation(program, "u_coordMat"), 1, GL_FALSE, m_coordMat.getColumnMajorData().getPtr());
506	gl.uniform4fv(gl.getUniformLocation(program, "u_scale"), 1, m_texScale.getPtr());
507	gl.uniform4fv(gl.getUniformLocation(program, "u_bias"), 1, m_texBias.getPtr());
508}
509
510void TextureCubeShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
511{
512	tcu::Mat3 texCoordMat = tcu::Mat3(m_uniforms[0].value.m3);
513
514	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
515	{
516		rr::VertexPacket&	packet	= *packets[packetNdx];
517		tcu::Vec2			a_coord = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx).xy();
518		tcu::Vec3			v_coord = texCoordMat * tcu::Vec3(a_coord.x(), a_coord.y(), 1.0f);
519
520		packet.position				= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
521		packet.outputs[0]			= tcu::Vec4(v_coord.x(), v_coord.y(), v_coord.z(), 0.0f);
522	}
523}
524
525void TextureCubeShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
526{
527	const tcu::Vec4 texScale (m_uniforms[2].value.f4);
528	const tcu::Vec4 texBias	 (m_uniforms[3].value.f4);
529
530	tcu::Vec3 texCoords[4];
531	tcu::Vec4 colors[4];
532
533	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
534	{
535		const sglr::rc::TextureCube* tex = m_uniforms[1].sampler.texCube;
536
537		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
538		{
539			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
540			texCoords[fragNdx] = tcu::Vec3(coord.x(), coord.y(), coord.z());
541		}
542
543		tex->sample4(colors, texCoords);
544
545		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
546		{
547			const tcu::Vec4		color	= colors[fragNdx] * texScale + texBias;
548			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
549			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
550
551			if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
552			else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
553			else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
554			else
555				DE_ASSERT(DE_FALSE);
556		}
557	}
558}
559
560Texture2DArrayShader::Texture2DArrayShader (glu::DataType samplerType, glu::DataType outputType)
561	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
562							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
563							<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
564							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
565							<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
566							<< sglr::pdec::Uniform("u_sampler0", samplerType)
567							<< sglr::pdec::Uniform("u_scale", glu::TYPE_FLOAT_VEC4)
568							<< sglr::pdec::Uniform("u_bias", glu::TYPE_FLOAT_VEC4)
569							<< sglr::pdec::Uniform("u_layer", glu::TYPE_INT)
570							<< sglr::pdec::VertexSource(
571									"#version 300 es\n"
572									"in highp vec4 a_position;\n"
573									"in highp vec2 a_coord;\n"
574									"out highp vec2 v_coord;\n"
575									"void main (void)\n"
576									"{\n"
577									"	gl_Position = a_position;\n"
578									"	v_coord = a_coord;\n"
579									"}\n")
580							<< sglr::pdec::FragmentSource(
581									string("") +
582									"#version 300 es\n"
583									"uniform highp " + glu::getDataTypeName(samplerType) + " u_sampler0;\n"
584									"uniform highp vec4 u_scale;\n"
585									"uniform highp vec4 u_bias;\n"
586									"uniform highp int u_layer;\n"
587									"in highp vec2 v_coord;\n"
588									"layout(location = 0) out highp " + glu::getDataTypeName(outputType) + " o_color;\n"
589									"void main (void)\n"
590									"{\n"
591									"	o_color = " + glu::getDataTypeName(outputType) + "(vec4(texture(u_sampler0, vec3(v_coord, u_layer))) * u_scale + u_bias);\n"
592									"}\n"))
593	, m_texScale	(1.0f)
594	, m_texBias		(0.0f)
595	, m_layer		(0)
596	, m_outputType	(outputType)
597{
598}
599
600void Texture2DArrayShader::setLayer (int layer)
601{
602	m_layer = layer;
603}
604
605void Texture2DArrayShader::setTexScaleBias (const Vec4& scale, const Vec4& bias)
606{
607	m_texScale	= scale;
608	m_texBias	= bias;
609}
610
611void Texture2DArrayShader::setUniforms (sglr::Context& gl, deUint32 program) const
612{
613	gl.useProgram(program);
614
615	gl.uniform1i	(gl.getUniformLocation(program, "u_sampler0"),	0);
616	gl.uniform1i	(gl.getUniformLocation(program, "u_layer"),		m_layer);
617	gl.uniform4fv	(gl.getUniformLocation(program, "u_scale"),		1, m_texScale.getPtr());
618	gl.uniform4fv	(gl.getUniformLocation(program, "u_bias"),		1, m_texBias.getPtr());
619}
620
621void Texture2DArrayShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
622{
623	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
624	{
625		rr::VertexPacket& packet = *packets[packetNdx];
626
627		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
628		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
629	}
630}
631
632void Texture2DArrayShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
633{
634	const tcu::Vec4 texScale	(m_uniforms[1].value.f4);
635	const tcu::Vec4 texBias		(m_uniforms[2].value.f4);
636	const int		layer		= m_uniforms[3].value.i;
637
638	tcu::Vec3 texCoords[4];
639	tcu::Vec4 colors[4];
640
641	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
642	{
643		const sglr::rc::Texture2DArray* tex = m_uniforms[0].sampler.tex2DArray;
644
645		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
646		{
647			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
648			texCoords[fragNdx] = tcu::Vec3(coord.x(), coord.y(), float(layer));
649		}
650
651		tex->sample4(colors, texCoords);
652
653		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
654		{
655			const tcu::Vec4		color	= colors[fragNdx] * texScale + texBias;
656			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
657			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
658
659			if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
660			else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
661			else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
662			else
663				DE_ASSERT(DE_FALSE);
664		}
665	}
666}
667
668Texture3DShader::Texture3DShader (glu::DataType samplerType, glu::DataType outputType)
669	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
670							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
671							<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
672							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
673							<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
674							<< sglr::pdec::Uniform("u_sampler0", samplerType)
675							<< sglr::pdec::Uniform("u_scale", glu::TYPE_FLOAT_VEC4)
676							<< sglr::pdec::Uniform("u_bias", glu::TYPE_FLOAT_VEC4)
677							<< sglr::pdec::Uniform("u_depth", glu::TYPE_FLOAT)
678							<< sglr::pdec::VertexSource(
679									"#version 300 es\n"
680									"in highp vec4 a_position;\n"
681									"in highp vec2 a_coord;\n"
682									"out highp vec2 v_coord;\n"
683									"void main (void)\n"
684									"{\n"
685									"	gl_Position = a_position;\n"
686									"	v_coord = a_coord;\n"
687									"}\n")
688							<< sglr::pdec::FragmentSource(
689									string("") +
690									"#version 300 es\n"
691									"uniform highp " + glu::getDataTypeName(samplerType) + " u_sampler0;\n"
692									"uniform highp vec4 u_scale;\n"
693									"uniform highp vec4 u_bias;\n"
694									"uniform highp float u_depth;\n"
695									"in highp vec2 v_coord;\n"
696									"layout(location = 0) out highp " + glu::getDataTypeName(outputType) + " o_color;\n"
697									"void main (void)\n"
698									"{\n"
699									"	o_color = " + glu::getDataTypeName(outputType) + "(vec4(texture(u_sampler0, vec3(v_coord, u_depth))) * u_scale + u_bias);\n"
700									"}\n"))
701	, m_texScale	(1.0f)
702	, m_texBias		(0.0f)
703	, m_depth		(0.0f)
704	, m_outputType	(outputType)
705{
706}
707
708void Texture3DShader::setDepth (float depth)
709{
710	m_depth = depth;
711}
712
713void Texture3DShader::setTexScaleBias (const Vec4& scale, const Vec4& bias)
714{
715	m_texScale	= scale;
716	m_texBias	= bias;
717}
718
719void Texture3DShader::setUniforms (sglr::Context& gl, deUint32 program) const
720{
721	gl.useProgram(program);
722
723	gl.uniform1i	(gl.getUniformLocation(program, "u_sampler0"),	0);
724	gl.uniform1f	(gl.getUniformLocation(program, "u_depth"),		m_depth);
725	gl.uniform4fv	(gl.getUniformLocation(program, "u_scale"),		1, m_texScale.getPtr());
726	gl.uniform4fv	(gl.getUniformLocation(program, "u_bias"),		1, m_texBias.getPtr());
727}
728
729void Texture3DShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
730{
731	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
732	{
733		rr::VertexPacket& packet = *packets[packetNdx];
734
735		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
736		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
737	}
738}
739
740void Texture3DShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
741{
742	const tcu::Vec4 texScale	(m_uniforms[1].value.f4);
743	const tcu::Vec4 texBias		(m_uniforms[2].value.f4);
744	const float		depth		= m_uniforms[3].value.f;
745
746	tcu::Vec3 texCoords[4];
747	tcu::Vec4 colors[4];
748
749	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
750	{
751		const sglr::rc::Texture3D* tex = m_uniforms[0].sampler.tex3D;
752
753		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
754		{
755			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
756			texCoords[fragNdx] = tcu::Vec3(coord.x(), coord.y(), depth);
757		}
758
759		tex->sample4(colors, texCoords);
760
761		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
762		{
763			const tcu::Vec4		color	= colors[fragNdx] * texScale + texBias;
764			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
765			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
766
767			if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
768			else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
769			else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
770			else
771				DE_ASSERT(DE_FALSE);
772		}
773	}
774}
775
776DepthGradientShader::DepthGradientShader (glu::DataType outputType)
777	: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
778					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
779					<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
780					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
781					<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
782					<< sglr::pdec::Uniform("u_maxGradient", glu::TYPE_FLOAT)
783					<< sglr::pdec::Uniform("u_minGradient", glu::TYPE_FLOAT)
784					<< sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
785					<< sglr::pdec::VertexSource(
786							"#version 300 es\n"
787							"in highp vec4 a_position;\n"
788							"in highp vec4 a_coord;\n"
789							"out highp vec4 v_coord;\n"
790							"void main (void)\n"
791							"{\n"
792							"	gl_Position = a_position;\n"
793							"	v_coord = a_coord;\n"
794							"}\n")
795					<< sglr::pdec::FragmentSource(
796							string(
797								"#version 300 es\n"
798								"in highp vec4 v_coord;\n"
799								"uniform highp float u_minGradient;\n"
800								"uniform highp float u_maxGradient;\n"
801								"uniform highp vec4 u_color;\n"
802								"layout(location = 0) out highp ") + glu::getDataTypeName(outputType) + " o_color;\n"
803								"void main (void)\n"
804								"{\n"
805								"	highp float x = v_coord.x;\n"
806								"	highp float y = v_coord.y;\n"
807								"	highp float f0 = (x + y) * 0.5;\n"
808								"	gl_FragDepth = u_minGradient + (u_maxGradient-u_minGradient)*f0;\n"
809								"	o_color = " + glu::getDataTypeName(outputType) + "(u_color);\n"
810								"}\n"))
811	, m_outputType	(outputType)
812	, u_minGradient	(getUniformByName("u_minGradient"))
813	, u_maxGradient	(getUniformByName("u_maxGradient"))
814	, u_color		(getUniformByName("u_color"))
815{
816}
817
818void DepthGradientShader::setUniforms (sglr::Context& ctx, deUint32 program, const float gradientMin, const float gradientMax, const tcu::Vec4& color)
819{
820	ctx.useProgram(program);
821	ctx.uniform1fv(ctx.getUniformLocation(program, "u_minGradient"), 1, &gradientMin);
822	ctx.uniform1fv(ctx.getUniformLocation(program, "u_maxGradient"), 1, &gradientMax);
823	ctx.uniform4fv(ctx.getUniformLocation(program, "u_color"), 1, color.getPtr());
824}
825
826void DepthGradientShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
827{
828	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
829	{
830		rr::VertexPacket& packet = *packets[packetNdx];
831
832		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
833		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
834	}
835}
836
837void DepthGradientShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
838{
839	const float			gradientMin	(u_minGradient.value.f);
840	const float			gradientMax	(u_maxGradient.value.f);
841	const tcu::Vec4		color		(u_color.value.f4);
842	const tcu::IVec4	icolor		(castVectorSaturate<deInt32>(color));
843	const tcu::UVec4	uicolor		(castVectorSaturate<deUint32>(color));
844
845	// running this shader without a depth buffer does not make any sense
846	DE_ASSERT(context.fragmentDepths);
847
848	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
849	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
850	{
851		const tcu::Vec4		coord	= rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
852		const float			x		= coord.x();
853		const float			y		= coord.y();
854		const float			f0		= (x + y) * 0.5f;
855
856		rr::writeFragmentDepth(context, packetNdx, fragNdx, 0, gradientMin + (gradientMax-gradientMin) * f0);
857
858		if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
859		else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
860		else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
861		else
862			DE_ASSERT(DE_FALSE);
863	}
864}
865
866void clearColorBuffer (sglr::Context& ctx, const tcu::TextureFormat& format, const tcu::Vec4& value)
867{
868	const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(format.type);
869
870	switch (fmtClass)
871	{
872		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
873		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
874		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
875			ctx.clearBufferfv(GL_COLOR, 0, value.getPtr());
876			break;
877
878		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
879			ctx.clearBufferuiv(GL_COLOR, 0, value.asUint().getPtr());
880			break;
881
882		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
883			ctx.clearBufferiv(GL_COLOR, 0, value.asInt().getPtr());
884			break;
885
886		default:
887			DE_ASSERT(DE_FALSE);
888	}
889}
890
891void readPixels (sglr::Context& ctx, tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias)
892{
893	tcu::TextureFormat		readFormat		= getFramebufferReadFormat(format);
894	glu::TransferFormat		transferFmt		= glu::getTransferFormat(readFormat);
895	int						alignment		= 4; // \note GL_PACK_ALIGNMENT = 4 is assumed.
896	int						rowSize			= deAlign32(readFormat.getPixelSize()*width, alignment);
897	vector<deUint8>			data			(rowSize*height);
898
899	ctx.readPixels(x, y, width, height, transferFmt.format, transferFmt.dataType, &data[0]);
900
901	// Convert to surface.
902	tcu::ConstPixelBufferAccess src(readFormat, width, height, 1, rowSize, 0, &data[0]);
903
904	dst.setSize(width, height);
905	tcu::PixelBufferAccess dstAccess = dst.getAccess();
906
907	for (int yo = 0; yo < height; yo++)
908	for (int xo = 0; xo < width; xo++)
909		dstAccess.setPixel(src.getPixel(xo, yo) * scale + bias, xo, yo);
910}
911
912static const char* getFboIncompleteReasonName (deUint32 reason)
913{
914	switch (reason)
915	{
916		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:			return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
917		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:	return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
918		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:			return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
919		case GL_FRAMEBUFFER_UNSUPPORTED:					return "GL_FRAMEBUFFER_UNSUPPORTED";
920		case GL_FRAMEBUFFER_COMPLETE:						return "GL_FRAMEBUFFER_COMPLETE";
921		default:											return "UNKNOWN";
922	}
923}
924
925FboIncompleteException::FboIncompleteException (deUint32 reason, const char* file, int line)
926	: TestError		("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
927	, m_reason		(reason)
928{
929}
930
931const char* getFormatName (deUint32 format)
932{
933	switch (format)
934	{
935		case GL_RGB565:				return "rgb565";
936		case GL_RGB5_A1:			return "rgb5_a1";
937		case GL_RGBA4:				return "rgba4";
938		case GL_DEPTH_COMPONENT16:	return "depth_component16";
939		case GL_STENCIL_INDEX8:		return "stencil_index8";
940		case GL_RGBA32F:			return "rgba32f";
941		case GL_RGBA32I:			return "rgba32i";
942		case GL_RGBA32UI:			return "rgba32ui";
943		case GL_RGBA16F:			return "rgba16f";
944		case GL_RGBA16I:			return "rgba16i";
945		case GL_RGBA16UI:			return "rgba16ui";
946		case GL_RGBA8:				return "rgba8";
947		case GL_RGBA8I:				return "rgba8i";
948		case GL_RGBA8UI:			return "rgba8ui";
949		case GL_SRGB8_ALPHA8:		return "srgb8_alpha8";
950		case GL_RGB10_A2:			return "rgb10_a2";
951		case GL_RGB10_A2UI:			return "rgb10_a2ui";
952		case GL_RGBA8_SNORM:		return "rgba8_snorm";
953		case GL_RGB8:				return "rgb8";
954		case GL_R11F_G11F_B10F:		return "r11f_g11f_b10f";
955		case GL_RGB32F:				return "rgb32f";
956		case GL_RGB32I:				return "rgb32i";
957		case GL_RGB32UI:			return "rgb32ui";
958		case GL_RGB16F:				return "rgb16f";
959		case GL_RGB16I:				return "rgb16i";
960		case GL_RGB16UI:			return "rgb16ui";
961		case GL_RGB8_SNORM:			return "rgb8_snorm";
962		case GL_RGB8I:				return "rgb8i";
963		case GL_RGB8UI:				return "rgb8ui";
964		case GL_SRGB8:				return "srgb8";
965		case GL_RGB9_E5:			return "rgb9_e5";
966		case GL_RG32F:				return "rg32f";
967		case GL_RG32I:				return "rg32i";
968		case GL_RG32UI:				return "rg32ui";
969		case GL_RG16F:				return "rg16f";
970		case GL_RG16I:				return "rg16i";
971		case GL_RG16UI:				return "rg16ui";
972		case GL_RG8:				return "rg8";
973		case GL_RG8I:				return "rg8i";
974		case GL_RG8UI:				return "rg8ui";
975		case GL_RG8_SNORM:			return "rg8_snorm";
976		case GL_R32F:				return "r32f";
977		case GL_R32I:				return "r32i";
978		case GL_R32UI:				return "r32ui";
979		case GL_R16F:				return "r16f";
980		case GL_R16I:				return "r16i";
981		case GL_R16UI:				return "r16ui";
982		case GL_R8:					return "r8";
983		case GL_R8I:				return "r8i";
984		case GL_R8UI:				return "r8ui";
985		case GL_R8_SNORM:			return "r8_snorm";
986		case GL_DEPTH_COMPONENT32F:	return "depth_component32f";
987		case GL_DEPTH_COMPONENT24:	return "depth_component24";
988		case GL_DEPTH32F_STENCIL8:	return "depth32f_stencil8";
989		case GL_DEPTH24_STENCIL8:	return "depth24_stencil8";
990
991		default:
992			TCU_FAIL("Unknown format");
993	}
994}
995
996glu::DataType getFragmentOutputType (const tcu::TextureFormat& format)
997{
998	switch (tcu::getTextureChannelClass(format.type))
999	{
1000		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1001		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1002		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1003			return glu::TYPE_FLOAT_VEC4;
1004
1005		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1006			return glu::TYPE_UINT_VEC4;
1007
1008		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1009			return glu::TYPE_INT_VEC4;
1010
1011		default:
1012			DE_FATAL("Unknown format");
1013			return glu::TYPE_LAST;
1014	}
1015}
1016
1017tcu::TextureFormat getFramebufferReadFormat (const tcu::TextureFormat& format)
1018{
1019	switch (tcu::getTextureChannelClass(format.type))
1020	{
1021		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1022			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1023
1024		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1025		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1026			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1027
1028		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1029			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
1030
1031		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1032			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
1033
1034		default:
1035			DE_FATAL("Unknown format");
1036			return tcu::TextureFormat();
1037	}
1038}
1039
1040static int calculateU8ConversionError (int srcBits)
1041{
1042	if (srcBits > 0)
1043	{
1044		const int clampedBits	= de::clamp<int>(srcBits, 0, 8);
1045		const int srcMaxValue	= de::max((1<<clampedBits) - 1, 1);
1046		const int error			= int(deFloatCeil(255.0f * 2.0f / float(srcMaxValue)));
1047
1048		return de::clamp<int>(error, 0, 255);
1049	}
1050	else
1051		return 1;
1052}
1053
1054tcu::RGBA getFormatThreshold (const tcu::TextureFormat& format)
1055{
1056	const tcu::IVec4 bits = tcu::getTextureFormatMantissaBitDepth(format);
1057
1058	return tcu::RGBA(calculateU8ConversionError(bits.x()),
1059					 calculateU8ConversionError(bits.y()),
1060					 calculateU8ConversionError(bits.z()),
1061					 calculateU8ConversionError(bits.w()));
1062}
1063
1064tcu::RGBA getFormatThreshold (deUint32 glFormat)
1065{
1066	const tcu::TextureFormat format = glu::mapGLInternalFormat(glFormat);
1067
1068	return getFormatThreshold(format);
1069}
1070
1071static int getToSRGB8ConversionError (int srcBits)
1072{
1073	// \note These are pre-computed based on simulation results.
1074	static const int errors[] =
1075	{
1076		1,		// 0 bits - rounding
1077		255,	// 1 bits
1078		157,	// 2 bits
1079		106,	// 3 bits
1080		74,		// 4 bits
1081		51,		// 5 bits
1082		34,		// 6 bits
1083		22,		// 7 bits
1084		13,		// 8 bits
1085		7,		// 9 bits
1086		4,		// 10 bits
1087		3,		// 11 bits
1088		2,		// 12 bits
1089		// 1 from this on
1090	};
1091
1092	DE_ASSERT(srcBits >= 0);
1093	if (srcBits < DE_LENGTH_OF_ARRAY(errors))
1094		return errors[srcBits];
1095	else
1096		return 1;
1097}
1098
1099tcu::RGBA getToSRGBConversionThreshold (const tcu::TextureFormat& src, const tcu::TextureFormat& dst)
1100{
1101	// Only SRGB8 and SRGB8_ALPHA8 formats are supported.
1102	DE_ASSERT(dst.type == tcu::TextureFormat::UNORM_INT8 && tcu::isSRGB(dst));
1103
1104	const tcu::IVec4	bits		= tcu::getTextureFormatMantissaBitDepth(src);
1105	const bool			dstHasAlpha	= dst.order == tcu::TextureFormat::sRGBA;
1106
1107	return tcu::RGBA(getToSRGB8ConversionError(bits.x()),
1108					 getToSRGB8ConversionError(bits.y()),
1109					 getToSRGB8ConversionError(bits.z()),
1110					 dstHasAlpha ? calculateU8ConversionError(bits.w()) : 0);
1111}
1112
1113} // FboTestUtil
1114} // Functional
1115} // gles3
1116} // deqp
1117