Home | History | Annotate | Download | only in functional
      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 
     37 namespace deqp
     38 {
     39 namespace gles31
     40 {
     41 namespace Functional
     42 {
     43 namespace FboTestUtil
     44 {
     45 
     46 using std::string;
     47 using std::vector;
     48 using tcu::Vec2;
     49 using tcu::Vec3;
     50 using tcu::Vec4;
     51 using tcu::IVec2;
     52 using tcu::IVec3;
     53 using tcu::IVec4;
     54 
     55 static 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 
     68 template <typename T>
     69 static tcu::Vector<T, 4> castVectorSaturate (const tcu::Vec4& in)
     70 {
     71 	return tcu::Vector<T, 4>((in.x() + 0.5f >= std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : ((in.x() - 0.5f <= std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.x()))),
     72 	                         (in.y() + 0.5f >= std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : ((in.y() - 0.5f <= std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.y()))),
     73 							 (in.z() + 0.5f >= std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : ((in.z() - 0.5f <= std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.z()))),
     74 							 (in.w() + 0.5f >= std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : ((in.w() - 0.5f <= std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.w()))));
     75 }
     76 
     77 static 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 
    116 static 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 
    150 Texture2DShader::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 
    167 void Texture2DShader::setUnit (int inputNdx, int unitNdx)
    168 {
    169 	m_inputs[inputNdx].unitNdx = unitNdx;
    170 }
    171 
    172 void 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 
    178 void Texture2DShader::setOutScaleBias (const Vec4& scale, const Vec4& bias)
    179 {
    180 	m_outScale	= scale;
    181 	m_outBias	= bias;
    182 }
    183 
    184 void 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 
    203 void 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 
    214 void 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 
    265 TextureCubeArrayShader::TextureCubeArrayShader (glu::DataType samplerType, glu::DataType outputType)
    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 									"#version 310 es\n"
    278 									"#extension GL_EXT_texture_cube_map_array : require\n"
    279 									"in highp vec4 a_position;\n"
    280 									"in mediump vec2 a_coord;\n"
    281 									"uniform mat3 u_coordMat;\n"
    282 									"out highp vec3 v_coord;\n"
    283 									"void main (void)\n"
    284 									"{\n"
    285 									"	gl_Position = a_position;\n"
    286 									"	v_coord = u_coordMat * vec3(a_coord, 1.0);\n"
    287 									"}\n")
    288 							<< sglr::pdec::FragmentSource(
    289 									string("") +
    290 									"#version 310 es\n"
    291 									"#extension GL_EXT_texture_cube_map_array : require\n"
    292 									"uniform highp " + glu::getDataTypeName(samplerType) + " u_sampler0;\n"
    293 									"uniform highp vec4 u_scale;\n"
    294 									"uniform highp vec4 u_bias;\n"
    295 									"uniform highp int u_layer;\n"
    296 									"in highp vec3 v_coord;\n"
    297 									"layout(location = 0) out highp " + glu::getDataTypeName(outputType) + " o_color;\n"
    298 									"void main (void)\n"
    299 									"{\n"
    300 									"	o_color = " + glu::getDataTypeName(outputType) + "(vec4(texture(u_sampler0, vec4(v_coord, u_layer))) * u_scale + u_bias);\n"
    301 									"}\n"))
    302 	, m_texScale	(1.0f)
    303 	, m_texBias		(0.0f)
    304 	, m_layer		(0)
    305 	, m_outputType	(outputType)
    306 {
    307 }
    308 
    309 void TextureCubeArrayShader::setLayer (int layer)
    310 {
    311 	m_layer = layer;
    312 }
    313 
    314 void TextureCubeArrayShader::setFace (tcu::CubeFace face)
    315 {
    316 	static const float s_cubeTransforms[][3*3] =
    317 	{
    318 		// Face -X: (x, y, 1) -> (-1, -(2*y-1), +(2*x-1))
    319 		{  0.0f,  0.0f, -1.0f,
    320 		   0.0f, -2.0f,  1.0f,
    321 		   2.0f,  0.0f, -1.0f },
    322 		// Face +X: (x, y, 1) -> (+1, -(2*y-1), -(2*x-1))
    323 		{  0.0f,  0.0f,  1.0f,
    324 		   0.0f, -2.0f,  1.0f,
    325 		  -2.0f,  0.0f,  1.0f },
    326 		// Face -Y: (x, y, 1) -> (+(2*x-1), -1, -(2*y-1))
    327 		{  2.0f,  0.0f, -1.0f,
    328 		   0.0f,  0.0f, -1.0f,
    329 		   0.0f, -2.0f,  1.0f },
    330 		// Face +Y: (x, y, 1) -> (+(2*x-1), +1, +(2*y-1))
    331 		{  2.0f,  0.0f, -1.0f,
    332 		   0.0f,  0.0f,  1.0f,
    333 		   0.0f,  2.0f, -1.0f },
    334 		// Face -Z: (x, y, 1) -> (-(2*x-1), -(2*y-1), -1)
    335 		{ -2.0f,  0.0f,  1.0f,
    336 		   0.0f, -2.0f,  1.0f,
    337 		   0.0f,  0.0f, -1.0f },
    338 		// Face +Z: (x, y, 1) -> (+(2*x-1), -(2*y-1), +1)
    339 		{  2.0f,  0.0f, -1.0f,
    340 		   0.0f, -2.0f,  1.0f,
    341 		   0.0f,  0.0f,  1.0f }
    342 	};
    343 	DE_ASSERT(de::inBounds<int>(face, 0, tcu::CUBEFACE_LAST));
    344 	m_coordMat = tcu::Mat3(s_cubeTransforms[face]);
    345 }
    346 
    347 void TextureCubeArrayShader::setTexScaleBias (const Vec4& scale, const Vec4& bias)
    348 {
    349 	m_texScale	= scale;
    350 	m_texBias	= bias;
    351 }
    352 
    353 void TextureCubeArrayShader::setUniforms (sglr::Context& gl, deUint32 program) const
    354 {
    355 	gl.useProgram(program);
    356 
    357 	gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), 0);
    358 	gl.uniformMatrix3fv(gl.getUniformLocation(program, "u_coordMat"), 1, GL_FALSE, m_coordMat.getColumnMajorData().getPtr());
    359 	gl.uniform1i(gl.getUniformLocation(program, "u_layer"), m_layer);
    360 	gl.uniform4fv(gl.getUniformLocation(program, "u_scale"), 1, m_texScale.getPtr());
    361 	gl.uniform4fv(gl.getUniformLocation(program, "u_bias"), 1, m_texBias.getPtr());
    362 }
    363 
    364 void TextureCubeArrayShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
    365 {
    366 	tcu::Mat3 texCoordMat = tcu::Mat3(m_uniforms[0].value.m3);
    367 
    368 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    369 	{
    370 		rr::VertexPacket&	packet	= *packets[packetNdx];
    371 		const tcu::Vec2		a_coord = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx).xy();
    372 		const tcu::Vec3		v_coord = texCoordMat * tcu::Vec3(a_coord.x(), a_coord.y(), 1.0f);
    373 
    374 		packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
    375 		packet.outputs[0] = tcu::Vec4(v_coord.x(), v_coord.y(), v_coord.z(), 0.0f);
    376 	}
    377 }
    378 
    379 void TextureCubeArrayShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
    380 {
    381 	const tcu::Vec4 texScale (m_uniforms[2].value.f4);
    382 	const tcu::Vec4 texBias	 (m_uniforms[3].value.f4);
    383 
    384 	tcu::Vec4 texCoords[4];
    385 	tcu::Vec4 colors[4];
    386 
    387 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    388 	{
    389 		const sglr::rc::TextureCubeArray* tex = m_uniforms[1].sampler.texCubeArray;
    390 
    391 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
    392 		{
    393 			const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
    394 			texCoords[fragNdx] = tcu::Vec4(coord.x(), coord.y(), coord.z(), (float)m_layer);
    395 		}
    396 
    397 		tex->sample4(colors, texCoords);
    398 
    399 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
    400 		{
    401 			const tcu::Vec4		color	= colors[fragNdx] * texScale + texBias;
    402 			const tcu::IVec4	icolor	= castVectorSaturate<deInt32>(color);
    403 			const tcu::UVec4	uicolor	= castVectorSaturate<deUint32>(color);
    404 
    405 			if (m_outputType == glu::TYPE_FLOAT_VEC4)		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
    406 			else if (m_outputType == glu::TYPE_INT_VEC4)	rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
    407 			else if (m_outputType == glu::TYPE_UINT_VEC4)	rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
    408 			else
    409 				DE_ASSERT(DE_FALSE);
    410 		}
    411 	}
    412 }
    413 
    414 void clearColorBuffer (sglr::Context& ctx, const tcu::TextureFormat& format, const tcu::Vec4& value)
    415 {
    416 	const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(format.type);
    417 
    418 	switch (fmtClass)
    419 	{
    420 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
    421 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
    422 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
    423 			ctx.clearBufferfv(GL_COLOR, 0, value.getPtr());
    424 			break;
    425 
    426 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
    427 			ctx.clearBufferuiv(GL_COLOR, 0, value.asUint().getPtr());
    428 			break;
    429 
    430 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
    431 			ctx.clearBufferiv(GL_COLOR, 0, value.asInt().getPtr());
    432 			break;
    433 
    434 		default:
    435 			DE_ASSERT(DE_FALSE);
    436 	}
    437 }
    438 
    439 void 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)
    440 {
    441 	tcu::TextureFormat		readFormat		= getFramebufferReadFormat(format);
    442 	glu::TransferFormat		transferFmt		= glu::getTransferFormat(readFormat);
    443 	int						alignment		= 4; // \note GL_PACK_ALIGNMENT = 4 is assumed.
    444 	int						rowSize			= deAlign32(readFormat.getPixelSize()*width, alignment);
    445 	vector<deUint8>			data			(rowSize*height);
    446 
    447 	ctx.readPixels(x, y, width, height, transferFmt.format, transferFmt.dataType, &data[0]);
    448 
    449 	// Convert to surface.
    450 	tcu::ConstPixelBufferAccess src(readFormat, width, height, 1, rowSize, 0, &data[0]);
    451 
    452 	dst.setSize(width, height);
    453 	tcu::PixelBufferAccess dstAccess = dst.getAccess();
    454 
    455 	for (int yo = 0; yo < height; yo++)
    456 	for (int xo = 0; xo < width; xo++)
    457 		dstAccess.setPixel(src.getPixel(xo, yo) * scale + bias, xo, yo);
    458 }
    459 
    460 static const char* getFboIncompleteReasonName (deUint32 reason)
    461 {
    462 	switch (reason)
    463 	{
    464 		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:			return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
    465 		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:	return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
    466 		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:			return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
    467 		case GL_FRAMEBUFFER_UNSUPPORTED:					return "GL_FRAMEBUFFER_UNSUPPORTED";
    468 		case GL_FRAMEBUFFER_COMPLETE:						return "GL_FRAMEBUFFER_COMPLETE";
    469 		default:											return "UNKNOWN";
    470 	}
    471 }
    472 
    473 FboIncompleteException::FboIncompleteException (deUint32 reason, const char* file, int line)
    474 	: TestError		("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
    475 	, m_reason		(reason)
    476 {
    477 }
    478 
    479 const char* getFormatName (deUint32 format)
    480 {
    481 	switch (format)
    482 	{
    483 		case GL_RGB565:				return "rgb565";
    484 		case GL_RGB5_A1:			return "rgb5_a1";
    485 		case GL_RGBA4:				return "rgba4";
    486 		case GL_DEPTH_COMPONENT16:	return "depth_component16";
    487 		case GL_STENCIL_INDEX8:		return "stencil_index8";
    488 		case GL_RGBA32F:			return "rgba32f";
    489 		case GL_RGBA32I:			return "rgba32i";
    490 		case GL_RGBA32UI:			return "rgba32ui";
    491 		case GL_RGBA16F:			return "rgba16f";
    492 		case GL_RGBA16I:			return "rgba16i";
    493 		case GL_RGBA16UI:			return "rgba16ui";
    494 		case GL_RGBA8:				return "rgba8";
    495 		case GL_RGBA8I:				return "rgba8i";
    496 		case GL_RGBA8UI:			return "rgba8ui";
    497 		case GL_SRGB8_ALPHA8:		return "srgb8_alpha8";
    498 		case GL_RGB10_A2:			return "rgb10_a2";
    499 		case GL_RGB10_A2UI:			return "rgb10_a2ui";
    500 		case GL_RGBA8_SNORM:		return "rgba8_snorm";
    501 		case GL_RGB8:				return "rgb8";
    502 		case GL_R11F_G11F_B10F:		return "r11f_g11f_b10f";
    503 		case GL_RGB32F:				return "rgb32f";
    504 		case GL_RGB32I:				return "rgb32i";
    505 		case GL_RGB32UI:			return "rgb32ui";
    506 		case GL_RGB16F:				return "rgb16f";
    507 		case GL_RGB16I:				return "rgb16i";
    508 		case GL_RGB16UI:			return "rgb16ui";
    509 		case GL_RGB8_SNORM:			return "rgb8_snorm";
    510 		case GL_RGB8I:				return "rgb8i";
    511 		case GL_RGB8UI:				return "rgb8ui";
    512 		case GL_SRGB8:				return "srgb8";
    513 		case GL_RGB9_E5:			return "rgb9_e5";
    514 		case GL_RG32F:				return "rg32f";
    515 		case GL_RG32I:				return "rg32i";
    516 		case GL_RG32UI:				return "rg32ui";
    517 		case GL_RG16F:				return "rg16f";
    518 		case GL_RG16I:				return "rg16i";
    519 		case GL_RG16UI:				return "rg16ui";
    520 		case GL_RG8:				return "rg8";
    521 		case GL_RG8I:				return "rg8i";
    522 		case GL_RG8UI:				return "rg8ui";
    523 		case GL_RG8_SNORM:			return "rg8_snorm";
    524 		case GL_R32F:				return "r32f";
    525 		case GL_R32I:				return "r32i";
    526 		case GL_R32UI:				return "r32ui";
    527 		case GL_R16F:				return "r16f";
    528 		case GL_R16I:				return "r16i";
    529 		case GL_R16UI:				return "r16ui";
    530 		case GL_R8:					return "r8";
    531 		case GL_R8I:				return "r8i";
    532 		case GL_R8UI:				return "r8ui";
    533 		case GL_R8_SNORM:			return "r8_snorm";
    534 		case GL_DEPTH_COMPONENT32F:	return "depth_component32f";
    535 		case GL_DEPTH_COMPONENT24:	return "depth_component24";
    536 		case GL_DEPTH32F_STENCIL8:	return "depth32f_stencil8";
    537 		case GL_DEPTH24_STENCIL8:	return "depth24_stencil8";
    538 
    539 		default:
    540 			TCU_FAIL("Unknown format");
    541 	}
    542 }
    543 
    544 glu::DataType getFragmentOutputType (const tcu::TextureFormat& format)
    545 {
    546 	switch (tcu::getTextureChannelClass(format.type))
    547 	{
    548 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
    549 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
    550 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
    551 			return glu::TYPE_FLOAT_VEC4;
    552 
    553 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
    554 			return glu::TYPE_UINT_VEC4;
    555 
    556 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
    557 			return glu::TYPE_INT_VEC4;
    558 
    559 		default:
    560 			DE_FATAL("Unknown format");
    561 			return glu::TYPE_LAST;
    562 	}
    563 }
    564 
    565 tcu::TextureFormat getFramebufferReadFormat (const tcu::TextureFormat& format)
    566 {
    567 	switch (tcu::getTextureChannelClass(format.type))
    568 	{
    569 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
    570 			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
    571 
    572 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
    573 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
    574 			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
    575 
    576 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
    577 			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
    578 
    579 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
    580 			return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
    581 
    582 		default:
    583 			DE_FATAL("Unknown format");
    584 			return tcu::TextureFormat();
    585 	}
    586 }
    587 
    588 static int calculateU8ConversionError (int srcBits)
    589 {
    590 	if (srcBits > 0)
    591 	{
    592 		const int clampedBits	= de::clamp<int>(srcBits, 0, 8);
    593 		const int srcMaxValue	= de::max((1<<clampedBits) - 1, 1);
    594 		const int error			= int(deFloatCeil(255.0f * 2.0f / float(srcMaxValue)));
    595 
    596 		return de::clamp<int>(error, 0, 255);
    597 	}
    598 	else
    599 		return 1;
    600 }
    601 
    602 tcu::RGBA getFormatThreshold (const tcu::TextureFormat& format)
    603 {
    604 	const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(format);
    605 
    606 	return tcu::RGBA(calculateU8ConversionError(bits.x()),
    607 					 calculateU8ConversionError(bits.y()),
    608 					 calculateU8ConversionError(bits.z()),
    609 					 calculateU8ConversionError(bits.w()));
    610 }
    611 
    612 tcu::RGBA getFormatThreshold (deUint32 glFormat)
    613 {
    614 	const tcu::TextureFormat format = glu::mapGLInternalFormat(glFormat);
    615 
    616 	return getFormatThreshold(format);
    617 }
    618 
    619 } // FboTestUtil
    620 } // Functional
    621 } // gles31
    622 } // deqp
    623