1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 "es31fFboTestUtil.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 gles31
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
77static string genTexFragmentShader (const vector<glu::DataType>& samplerTypes, glu::DataType outputType)
78{
79	const char*			precision	= "highp";
80	std::ostringstream	src;
81
82	src << "#version 300 es\n"
83		<< "layout(location = 0) out highp " << glu::getDataTypeName(outputType) << " o_color0;\n";
84
85	src << "in highp vec2 v_coord;\n";
86
87	for (int samplerNdx = 0; samplerNdx < (int)samplerTypes.size(); samplerNdx++)
88	{
89		src << "uniform " << precision << " " << glu::getDataTypeName(samplerTypes[samplerNdx]) << " u_sampler" << samplerNdx << ";\n";
90		src << "uniform " << precision << " vec4 u_texScale" << samplerNdx << ";\n";
91		src << "uniform " << precision << " vec4 u_texBias" << samplerNdx << ";\n";
92	}
93
94	// Output scale & bias
95	src << "uniform " << precision << " vec4 u_outScale0;\n"
96		<< "uniform " << precision << " vec4 u_outBias0;\n";
97
98	src << "\n"
99		<< "void main (void)\n"
100		<< "{\n"
101		<< "	" << precision << " vec4 out0 = vec4(0.0);\n";
102
103	// Texture input fetch and combine.
104	for (int inNdx = 0; inNdx < (int)samplerTypes.size(); inNdx++)
105		src << "\tout0 += vec4("
106			<< "texture(u_sampler" << inNdx << ", v_coord)) * u_texScale" << inNdx << " + u_texBias" << inNdx << ";\n";
107
108	// Write output.
109	src << "	o_color0 = " << glu::getDataTypeName(outputType) << "(out0 * u_outScale0 + u_outBias0);\n";
110
111	src << "}\n";
112
113	return src.str();
114}
115
116static sglr::pdec::ShaderProgramDeclaration genTexture2DShaderDecl (const DataTypes& samplerTypes, glu::DataType outputType)
117{
118	sglr::pdec::ShaderProgramDeclaration decl;
119
120	decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT);
121	decl << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT);
122	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
123	decl << sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType));
124
125	decl << sglr::pdec::VertexSource(
126		"#version 300 es\n"
127		"in highp vec4 a_position;\n"
128		"in highp vec2 a_coord;\n"
129		"out highp vec2 v_coord;\n"
130		"void main(void)\n"
131		"{\n"
132		"	gl_Position = a_position;\n"
133		"	v_coord = a_coord;\n"
134		"}\n");
135	decl << sglr::pdec::FragmentSource(genTexFragmentShader(samplerTypes.vec, outputType));
136
137	decl << sglr::pdec::Uniform("u_outScale0", glu::TYPE_FLOAT_VEC4);
138	decl << sglr::pdec::Uniform("u_outBias0", glu::TYPE_FLOAT_VEC4);
139
140	for (size_t ndx = 0; ndx < samplerTypes.vec.size(); ++ndx)
141	{
142		decl << sglr::pdec::Uniform(std::string("u_sampler")  + de::toString(ndx), samplerTypes.vec[ndx]);
143		decl << sglr::pdec::Uniform(std::string("u_texScale") + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
144		decl << sglr::pdec::Uniform(std::string("u_texBias")  + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
145	}
146
147	return decl;
148}
149
150Texture2DShader::Texture2DShader (const DataTypes& samplerTypes, glu::DataType outputType, const Vec4& outScale, const Vec4& outBias)
151	: sglr::ShaderProgram	(genTexture2DShaderDecl(samplerTypes, outputType))
152	, m_outScale			(outScale)
153	, m_outBias				(outBias)
154	, m_outputType			(outputType)
155{
156	m_inputs.resize(samplerTypes.vec.size());
157
158	// Initialize units.
159	for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
160	{
161		m_inputs[ndx].unitNdx	= ndx;
162		m_inputs[ndx].scale		= Vec4(1.0f);
163		m_inputs[ndx].bias		= Vec4(0.0f);
164	}
165}
166
167void Texture2DShader::setUnit (int inputNdx, int unitNdx)
168{
169	m_inputs[inputNdx].unitNdx = unitNdx;
170}
171
172void Texture2DShader::setTexScaleBias (int inputNdx, const Vec4& scale, const Vec4& bias)
173{
174	m_inputs[inputNdx].scale	= scale;
175	m_inputs[inputNdx].bias		= bias;
176}
177
178void Texture2DShader::setOutScaleBias (const Vec4& scale, const Vec4& bias)
179{
180	m_outScale	= scale;
181	m_outBias	= bias;
182}
183
184void Texture2DShader::setUniforms (sglr::Context& gl, deUint32 program) const
185{
186	gl.useProgram(program);
187
188	for (int texNdx = 0; texNdx < (int)m_inputs.size(); texNdx++)
189	{
190		string	samplerName	= string("u_sampler") + de::toString(texNdx);
191		string	scaleName	= string("u_texScale") + de::toString(texNdx);
192		string	biasName	= string("u_texBias") + de::toString(texNdx);
193
194		gl.uniform1i(gl.getUniformLocation(program, samplerName.c_str()), m_inputs[texNdx].unitNdx);
195		gl.uniform4fv(gl.getUniformLocation(program, scaleName.c_str()), 1, m_inputs[texNdx].scale.getPtr());
196		gl.uniform4fv(gl.getUniformLocation(program, biasName.c_str()), 1, m_inputs[texNdx].bias.getPtr());
197	}
198
199	gl.uniform4fv(gl.getUniformLocation(program, "u_outScale0"), 1, m_outScale.getPtr());
200	gl.uniform4fv(gl.getUniformLocation(program, "u_outBias0"), 1, m_outBias.getPtr());
201}
202
203void Texture2DShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
204{
205	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
206	{
207		rr::VertexPacket& packet = *packets[packetNdx];
208
209		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
210		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
211	}
212}
213
214void Texture2DShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
215{
216	const tcu::Vec4 outScale (m_uniforms[0].value.f4);
217	const tcu::Vec4 outBias	 (m_uniforms[1].value.f4);
218
219	tcu::Vec2 texCoords[4];
220	tcu::Vec4 colors[4];
221
222	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
223	{
224		// setup tex coords
225		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
226		{
227			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
228			texCoords[fragNdx] = tcu::Vec2(coord.x(), coord.y());
229		}
230
231		// clear result
232		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
233			colors[fragNdx] = tcu::Vec4(0.0f);
234
235		// sample each texture
236		for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
237		{
238			const sglr::rc::Texture2D*	tex		= m_uniforms[2 + ndx*3].sampler.tex2D;
239			const tcu::Vec4				scale	(m_uniforms[2 + ndx*3 + 1].value.f4);
240			const tcu::Vec4				bias	(m_uniforms[2 + ndx*3 + 2].value.f4);
241			tcu::Vec4 tmpColors[4];
242
243			tex->sample4(tmpColors, texCoords);
244
245			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
246				colors[fragNdx] += tmpColors[fragNdx] * scale + bias;
247		}
248
249		// write out
250		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
251		{
252			const tcu::Vec4		color	= colors[fragNdx] * outScale + outBias;
253			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
254			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
255
256			if (m_outputType == glu::TYPE_FLOAT_VEC4)			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
257			else if (m_outputType == glu::TYPE_INT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
258			else if (m_outputType == glu::TYPE_UINT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
259			else
260				DE_ASSERT(DE_FALSE);
261		}
262	}
263}
264
265TextureCubeArrayShader::TextureCubeArrayShader (glu::DataType samplerType, glu::DataType outputType, glu::GLSLVersion glslVersion)
266	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
267							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
268							<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
269							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
270							<< sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType))
271							<< sglr::pdec::Uniform("u_coordMat", glu::TYPE_FLOAT_MAT3)
272							<< sglr::pdec::Uniform("u_sampler0", samplerType)
273							<< sglr::pdec::Uniform("u_scale", glu::TYPE_FLOAT_VEC4)
274							<< sglr::pdec::Uniform("u_bias", glu::TYPE_FLOAT_VEC4)
275							<< sglr::pdec::Uniform("u_layer", glu::TYPE_INT)
276							<< sglr::pdec::VertexSource(
277									string("") +
278									((glslVersion == glu::GLSL_VERSION_310_ES) ?
279									"#version 310 es\n"
280									"#extension GL_EXT_texture_cube_map_array : require\n"
281									 : "#version 320 es\n") +
282									"in highp vec4 a_position;\n"
283									"in mediump vec2 a_coord;\n"
284									"uniform mat3 u_coordMat;\n"
285									"out highp vec3 v_coord;\n"
286									"void main (void)\n"
287									"{\n"
288									"	gl_Position = a_position;\n"
289									"	v_coord = u_coordMat * vec3(a_coord, 1.0);\n"
290									"}\n")
291							<< sglr::pdec::FragmentSource(
292									string("") +
293									((glslVersion == glu::GLSL_VERSION_310_ES) ?
294									"#version 310 es\n"
295									"#extension GL_EXT_texture_cube_map_array : require\n"
296									 : "#version 320 es\n") +
297									"uniform highp " + glu::getDataTypeName(samplerType) + " u_sampler0;\n"
298									"uniform highp vec4 u_scale;\n"
299									"uniform highp vec4 u_bias;\n"
300									"uniform highp int u_layer;\n"
301									"in highp vec3 v_coord;\n"
302									"layout(location = 0) out highp " + glu::getDataTypeName(outputType) + " o_color;\n"
303									"void main (void)\n"
304									"{\n"
305									"	o_color = " + glu::getDataTypeName(outputType) + "(vec4(texture(u_sampler0, vec4(v_coord, u_layer))) * u_scale + u_bias);\n"
306									"}\n"))
307	, m_texScale	(1.0f)
308	, m_texBias		(0.0f)
309	, m_layer		(0)
310	, m_outputType	(outputType)
311{
312	TCU_CHECK_INTERNAL(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_320_ES);
313}
314
315void TextureCubeArrayShader::setLayer (int layer)
316{
317	m_layer = layer;
318}
319
320void TextureCubeArrayShader::setFace (tcu::CubeFace face)
321{
322	static const float s_cubeTransforms[][3*3] =
323	{
324		// Face -X: (x, y, 1) -> (-1, -(2*y-1), +(2*x-1))
325		{  0.0f,  0.0f, -1.0f,
326		   0.0f, -2.0f,  1.0f,
327		   2.0f,  0.0f, -1.0f },
328		// Face +X: (x, y, 1) -> (+1, -(2*y-1), -(2*x-1))
329		{  0.0f,  0.0f,  1.0f,
330		   0.0f, -2.0f,  1.0f,
331		  -2.0f,  0.0f,  1.0f },
332		// Face -Y: (x, y, 1) -> (+(2*x-1), -1, -(2*y-1))
333		{  2.0f,  0.0f, -1.0f,
334		   0.0f,  0.0f, -1.0f,
335		   0.0f, -2.0f,  1.0f },
336		// Face +Y: (x, y, 1) -> (+(2*x-1), +1, +(2*y-1))
337		{  2.0f,  0.0f, -1.0f,
338		   0.0f,  0.0f,  1.0f,
339		   0.0f,  2.0f, -1.0f },
340		// Face -Z: (x, y, 1) -> (-(2*x-1), -(2*y-1), -1)
341		{ -2.0f,  0.0f,  1.0f,
342		   0.0f, -2.0f,  1.0f,
343		   0.0f,  0.0f, -1.0f },
344		// Face +Z: (x, y, 1) -> (+(2*x-1), -(2*y-1), +1)
345		{  2.0f,  0.0f, -1.0f,
346		   0.0f, -2.0f,  1.0f,
347		   0.0f,  0.0f,  1.0f }
348	};
349	DE_ASSERT(de::inBounds<int>(face, 0, tcu::CUBEFACE_LAST));
350	m_coordMat = tcu::Mat3(s_cubeTransforms[face]);
351}
352
353void TextureCubeArrayShader::setTexScaleBias (const Vec4& scale, const Vec4& bias)
354{
355	m_texScale	= scale;
356	m_texBias	= bias;
357}
358
359void TextureCubeArrayShader::setUniforms (sglr::Context& gl, deUint32 program) const
360{
361	gl.useProgram(program);
362
363	gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), 0);
364	gl.uniformMatrix3fv(gl.getUniformLocation(program, "u_coordMat"), 1, GL_FALSE, m_coordMat.getColumnMajorData().getPtr());
365	gl.uniform1i(gl.getUniformLocation(program, "u_layer"), m_layer);
366	gl.uniform4fv(gl.getUniformLocation(program, "u_scale"), 1, m_texScale.getPtr());
367	gl.uniform4fv(gl.getUniformLocation(program, "u_bias"), 1, m_texBias.getPtr());
368}
369
370void TextureCubeArrayShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
371{
372	tcu::Mat3 texCoordMat = tcu::Mat3(m_uniforms[0].value.m3);
373
374	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
375	{
376		rr::VertexPacket&	packet	= *packets[packetNdx];
377		const tcu::Vec2		a_coord = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx).xy();
378		const tcu::Vec3		v_coord = texCoordMat * tcu::Vec3(a_coord.x(), a_coord.y(), 1.0f);
379
380		packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
381		packet.outputs[0] = tcu::Vec4(v_coord.x(), v_coord.y(), v_coord.z(), 0.0f);
382	}
383}
384
385void TextureCubeArrayShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
386{
387	const tcu::Vec4 texScale (m_uniforms[2].value.f4);
388	const tcu::Vec4 texBias	 (m_uniforms[3].value.f4);
389
390	tcu::Vec4 texCoords[4];
391	tcu::Vec4 colors[4];
392
393	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
394	{
395		const sglr::rc::TextureCubeArray* tex = m_uniforms[1].sampler.texCubeArray;
396
397		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
398		{
399			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
400			texCoords[fragNdx] = tcu::Vec4(coord.x(), coord.y(), coord.z(), (float)m_layer);
401		}
402
403		tex->sample4(colors, texCoords);
404
405		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
406		{
407			const tcu::Vec4		color	= colors[fragNdx] * texScale + texBias;
408			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
409			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
410
411			if (m_outputType == glu::TYPE_FLOAT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
412			else if (m_outputType == glu::TYPE_INT_VEC4)	rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
413			else if (m_outputType == glu::TYPE_UINT_VEC4)	rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
414			else
415				DE_ASSERT(DE_FALSE);
416		}
417	}
418}
419
420void clearColorBuffer (sglr::Context& ctx, const tcu::TextureFormat& format, const tcu::Vec4& value)
421{
422	const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(format.type);
423
424	switch (fmtClass)
425	{
426		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
427		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
428		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
429			ctx.clearBufferfv(GL_COLOR, 0, value.getPtr());
430			break;
431
432		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
433			ctx.clearBufferuiv(GL_COLOR, 0, value.asUint().getPtr());
434			break;
435
436		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
437			ctx.clearBufferiv(GL_COLOR, 0, value.asInt().getPtr());
438			break;
439
440		default:
441			DE_ASSERT(DE_FALSE);
442	}
443}
444
445void 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)
446{
447	tcu::TextureFormat		readFormat		= getFramebufferReadFormat(format);
448	glu::TransferFormat		transferFmt		= glu::getTransferFormat(readFormat);
449	int						alignment		= 4; // \note GL_PACK_ALIGNMENT = 4 is assumed.
450	int						rowSize			= deAlign32(readFormat.getPixelSize()*width, alignment);
451	vector<deUint8>			data			(rowSize*height);
452
453	ctx.readPixels(x, y, width, height, transferFmt.format, transferFmt.dataType, &data[0]);
454
455	// Convert to surface.
456	tcu::ConstPixelBufferAccess src(readFormat, width, height, 1, rowSize, 0, &data[0]);
457
458	dst.setSize(width, height);
459	tcu::PixelBufferAccess dstAccess = dst.getAccess();
460
461	for (int yo = 0; yo < height; yo++)
462	for (int xo = 0; xo < width; xo++)
463		dstAccess.setPixel(src.getPixel(xo, yo) * scale + bias, xo, yo);
464}
465
466static const char* getFboIncompleteReasonName (deUint32 reason)
467{
468	switch (reason)
469	{
470		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:			return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
471		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:	return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
472		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:			return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
473		case GL_FRAMEBUFFER_UNSUPPORTED:					return "GL_FRAMEBUFFER_UNSUPPORTED";
474		case GL_FRAMEBUFFER_COMPLETE:						return "GL_FRAMEBUFFER_COMPLETE";
475		default:											return "UNKNOWN";
476	}
477}
478
479FboIncompleteException::FboIncompleteException (deUint32 reason, const char* file, int line)
480	: TestError		("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
481	, m_reason		(reason)
482{
483}
484
485const char* getFormatName (deUint32 format)
486{
487	switch (format)
488	{
489		case GL_RGB565:				return "rgb565";
490		case GL_RGB5_A1:			return "rgb5_a1";
491		case GL_RGBA4:				return "rgba4";
492		case GL_DEPTH_COMPONENT16:	return "depth_component16";
493		case GL_STENCIL_INDEX8:		return "stencil_index8";
494		case GL_RGBA32F:			return "rgba32f";
495		case GL_RGBA32I:			return "rgba32i";
496		case GL_RGBA32UI:			return "rgba32ui";
497		case GL_RGBA16F:			return "rgba16f";
498		case GL_RGBA16I:			return "rgba16i";
499		case GL_RGBA16UI:			return "rgba16ui";
500		case GL_RGBA8:				return "rgba8";
501		case GL_RGBA8I:				return "rgba8i";
502		case GL_RGBA8UI:			return "rgba8ui";
503		case GL_SRGB8_ALPHA8:		return "srgb8_alpha8";
504		case GL_RGB10_A2:			return "rgb10_a2";
505		case GL_RGB10_A2UI:			return "rgb10_a2ui";
506		case GL_RGBA8_SNORM:		return "rgba8_snorm";
507		case GL_RGB8:				return "rgb8";
508		case GL_R11F_G11F_B10F:		return "r11f_g11f_b10f";
509		case GL_RGB32F:				return "rgb32f";
510		case GL_RGB32I:				return "rgb32i";
511		case GL_RGB32UI:			return "rgb32ui";
512		case GL_RGB16F:				return "rgb16f";
513		case GL_RGB16I:				return "rgb16i";
514		case GL_RGB16UI:			return "rgb16ui";
515		case GL_RGB8_SNORM:			return "rgb8_snorm";
516		case GL_RGB8I:				return "rgb8i";
517		case GL_RGB8UI:				return "rgb8ui";
518		case GL_SRGB8:				return "srgb8";
519		case GL_RGB9_E5:			return "rgb9_e5";
520		case GL_RG32F:				return "rg32f";
521		case GL_RG32I:				return "rg32i";
522		case GL_RG32UI:				return "rg32ui";
523		case GL_RG16F:				return "rg16f";
524		case GL_RG16I:				return "rg16i";
525		case GL_RG16UI:				return "rg16ui";
526		case GL_RG8:				return "rg8";
527		case GL_RG8I:				return "rg8i";
528		case GL_RG8UI:				return "rg8ui";
529		case GL_RG8_SNORM:			return "rg8_snorm";
530		case GL_R32F:				return "r32f";
531		case GL_R32I:				return "r32i";
532		case GL_R32UI:				return "r32ui";
533		case GL_R16F:				return "r16f";
534		case GL_R16I:				return "r16i";
535		case GL_R16UI:				return "r16ui";
536		case GL_R8:					return "r8";
537		case GL_R8I:				return "r8i";
538		case GL_R8UI:				return "r8ui";
539		case GL_R8_SNORM:			return "r8_snorm";
540		case GL_DEPTH_COMPONENT32F:	return "depth_component32f";
541		case GL_DEPTH_COMPONENT24:	return "depth_component24";
542		case GL_DEPTH32F_STENCIL8:	return "depth32f_stencil8";
543		case GL_DEPTH24_STENCIL8:	return "depth24_stencil8";
544
545		default:
546			TCU_FAIL("Unknown format");
547	}
548}
549
550glu::DataType getFragmentOutputType (const tcu::TextureFormat& format)
551{
552	switch (tcu::getTextureChannelClass(format.type))
553	{
554		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
555		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
556		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
557			return glu::TYPE_FLOAT_VEC4;
558
559		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
560			return glu::TYPE_UINT_VEC4;
561
562		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
563			return glu::TYPE_INT_VEC4;
564
565		default:
566			DE_FATAL("Unknown format");
567			return glu::TYPE_LAST;
568	}
569}
570
571tcu::TextureFormat getFramebufferReadFormat (const tcu::TextureFormat& format)
572{
573	switch (tcu::getTextureChannelClass(format.type))
574	{
575		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
576			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
577
578		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
579		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
580			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
581
582		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
583			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
584
585		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
586			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
587
588		default:
589			DE_FATAL("Unknown format");
590			return tcu::TextureFormat();
591	}
592}
593
594static int calculateU8ConversionError (int srcBits)
595{
596	if (srcBits > 0)
597	{
598		const int clampedBits	= de::clamp<int>(srcBits, 0, 8);
599		const int srcMaxValue	= de::max((1<<clampedBits) - 1, 1);
600		const int error			= int(deFloatCeil(255.0f * 2.0f / float(srcMaxValue)));
601
602		return de::clamp<int>(error, 0, 255);
603	}
604	else
605		return 1;
606}
607
608tcu::RGBA getFormatThreshold (const tcu::TextureFormat& format)
609{
610	const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(format);
611
612	return tcu::RGBA(calculateU8ConversionError(bits.x()),
613					 calculateU8ConversionError(bits.y()),
614					 calculateU8ConversionError(bits.z()),
615					 calculateU8ConversionError(bits.w()));
616}
617
618tcu::RGBA getFormatThreshold (deUint32 glFormat)
619{
620	const tcu::TextureFormat format = glu::mapGLInternalFormat(glFormat);
621
622	return getFormatThreshold(format);
623}
624
625} // FboTestUtil
626} // Functional
627} // gles31
628} // deqp
629