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 Floating-point packing and unpacking function tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fShaderPackingFunctionTests.hpp"
     25 #include "glsShaderExecUtil.hpp"
     26 #include "tcuTestLog.hpp"
     27 #include "tcuFormatUtil.hpp"
     28 #include "tcuFloat.hpp"
     29 #include "deRandom.hpp"
     30 #include "deMath.h"
     31 #include "deString.h"
     32 
     33 namespace deqp
     34 {
     35 namespace gles31
     36 {
     37 namespace Functional
     38 {
     39 
     40 using std::string;
     41 using tcu::TestLog;
     42 using namespace gls::ShaderExecUtil;
     43 
     44 namespace
     45 {
     46 
     47 inline deUint32 getUlpDiff (float a, float b)
     48 {
     49 	const deUint32	aBits	= tcu::Float32(a).bits();
     50 	const deUint32	bBits	= tcu::Float32(b).bits();
     51 	return aBits > bBits ? aBits - bBits : bBits - aBits;
     52 }
     53 
     54 struct HexFloat
     55 {
     56 	const float value;
     57 	HexFloat (const float value_) : value(value_) {}
     58 };
     59 
     60 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
     61 {
     62 	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
     63 }
     64 
     65 } // anonymous
     66 
     67 // ShaderPackingFunctionCase
     68 
     69 class ShaderPackingFunctionCase : public TestCase
     70 {
     71 public:
     72 								ShaderPackingFunctionCase	(Context& context, const char* name, const char* description, glu::ShaderType shaderType);
     73 								~ShaderPackingFunctionCase	(void);
     74 
     75 	void						init						(void);
     76 	void						deinit						(void);
     77 
     78 protected:
     79 	glu::ShaderType				m_shaderType;
     80 	ShaderSpec					m_spec;
     81 	ShaderExecutor*				m_executor;
     82 
     83 private:
     84 								ShaderPackingFunctionCase	(const ShaderPackingFunctionCase& other);
     85 	ShaderPackingFunctionCase&	operator=					(const ShaderPackingFunctionCase& other);
     86 };
     87 
     88 ShaderPackingFunctionCase::ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
     89 	: TestCase		(context, name, description)
     90 	, m_shaderType	(shaderType)
     91 	, m_executor	(DE_NULL)
     92 {
     93 	m_spec.version = glu::GLSL_VERSION_310_ES;
     94 }
     95 
     96 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
     97 {
     98 	ShaderPackingFunctionCase::deinit();
     99 }
    100 
    101 void ShaderPackingFunctionCase::init (void)
    102 {
    103 	DE_ASSERT(!m_executor);
    104 
    105 	m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
    106 	m_testCtx.getLog() << m_executor;
    107 
    108 	if (!m_executor->isOk())
    109 		throw tcu::TestError("Compile failed");
    110 }
    111 
    112 void ShaderPackingFunctionCase::deinit (void)
    113 {
    114 	delete m_executor;
    115 	m_executor = DE_NULL;
    116 }
    117 
    118 // Test cases
    119 
    120 static const char* getPrecisionPostfix (glu::Precision precision)
    121 {
    122 	static const char* s_postfix[] =
    123 	{
    124 		"_lowp",
    125 		"_mediump",
    126 		"_highp"
    127 	};
    128 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
    129 	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
    130 	return s_postfix[precision];
    131 }
    132 
    133 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
    134 {
    135 	static const char* s_postfix[] =
    136 	{
    137 		"_vertex",
    138 		"_fragment",
    139 		"_geometry",
    140 		"_tess_control",
    141 		"_tess_eval",
    142 		"_compute"
    143 	};
    144 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
    145 	return s_postfix[shaderType];
    146 }
    147 
    148 class PackSnorm2x16Case : public ShaderPackingFunctionCase
    149 {
    150 public:
    151 	PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
    152 		: ShaderPackingFunctionCase	(context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
    153 		, m_precision				(precision)
    154 	{
    155 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
    156 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    157 
    158 		m_spec.source = "out0 = packSnorm2x16(in0);";
    159 	}
    160 
    161 	IterateResult iterate (void)
    162 	{
    163 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    164 		std::vector<tcu::Vec2>		inputs;
    165 		std::vector<deUint32>		outputs;
    166 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1		:		// Rounding only.
    167 												  m_precision == glu::PRECISION_MEDIUMP	? 33	:		// (2^-10) * (2^15) + 1
    168 												  m_precision == glu::PRECISION_LOWP	? 129	: 0;	// (2^-8) * (2^15) + 1
    169 
    170 		// Special values to check.
    171 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
    172 		inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
    173 		inputs.push_back(tcu::Vec2(0.5f, -0.5f));
    174 		inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
    175 		inputs.push_back(tcu::Vec2(0.25f, -0.75f));
    176 
    177 		// Random values, mostly in range.
    178 		for (int ndx = 0; ndx < 15; ndx++)
    179 		{
    180 			const float x = rnd.getFloat()*2.5f - 1.25f;
    181 			const float y = rnd.getFloat()*2.5f - 1.25f;
    182 			inputs.push_back(tcu::Vec2(x, y));
    183 		}
    184 
    185 		// Large random values.
    186 		for (int ndx = 0; ndx < 80; ndx++)
    187 		{
    188 			const float x = rnd.getFloat()*1e6f - 0.5e6f;
    189 			const float y = rnd.getFloat()*1e6f - 0.5e6f;
    190 			inputs.push_back(tcu::Vec2(x, y));
    191 		}
    192 
    193 		outputs.resize(inputs.size());
    194 
    195 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    196 
    197 		{
    198 			const void*	in	= &inputs[0];
    199 			void*		out	= &outputs[0];
    200 
    201 			m_executor->useProgram();
    202 			m_executor->execute((int)inputs.size(), &in, &out);
    203 		}
    204 
    205 		// Verify
    206 		{
    207 			const int	numValues	= (int)inputs.size();
    208 			const int	maxPrints	= 10;
    209 			int			numFailed	= 0;
    210 
    211 			for (int valNdx = 0; valNdx < numValues; valNdx++)
    212 			{
    213 				const deUint16	ref0	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
    214 				const deUint16	ref1	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
    215 				const deUint32	ref		= (ref1 << 16) | ref0;
    216 				const deUint32	res		= outputs[valNdx];
    217 				const deUint16	res0	= (deUint16)(res & 0xffff);
    218 				const deUint16	res1	= (deUint16)(res >> 16);
    219 				const int		diff0	= de::abs((int)ref0 - (int)res0);
    220 				const int		diff1	= de::abs((int)ref1 - (int)res1);
    221 
    222 				if (diff0 > maxDiff || diff1 > maxDiff)
    223 				{
    224 					if (numFailed < maxPrints)
    225 					{
    226 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
    227 															   << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
    228 															   << ", got " << tcu::toHex(res)
    229 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    230 										   << TestLog::EndMessage;
    231 					}
    232 					else if (numFailed == maxPrints)
    233 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    234 
    235 					numFailed += 1;
    236 				}
    237 			}
    238 
    239 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    240 
    241 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    242 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    243 		}
    244 
    245 		return STOP;
    246 	}
    247 
    248 private:
    249 	glu::Precision m_precision;
    250 };
    251 
    252 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
    253 {
    254 public:
    255 	UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType)
    256 		: ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
    257 	{
    258 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    259 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
    260 
    261 		m_spec.source = "out0 = unpackSnorm2x16(in0);";
    262 	}
    263 
    264 	IterateResult iterate (void)
    265 	{
    266 		const deUint32				maxDiff		= 1; // Rounding error.
    267 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    268 		std::vector<deUint32>		inputs;
    269 		std::vector<tcu::Vec2>		outputs;
    270 
    271 		inputs.push_back(0x00000000u);
    272 		inputs.push_back(0x7fff8000u);
    273 		inputs.push_back(0x80007fffu);
    274 		inputs.push_back(0xffffffffu);
    275 		inputs.push_back(0x0001fffeu);
    276 
    277 		// Random values.
    278 		for (int ndx = 0; ndx < 95; ndx++)
    279 			inputs.push_back(rnd.getUint32());
    280 
    281 		outputs.resize(inputs.size());
    282 
    283 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    284 
    285 		{
    286 			const void*	in	= &inputs[0];
    287 			void*		out	= &outputs[0];
    288 
    289 			m_executor->useProgram();
    290 			m_executor->execute((int)inputs.size(), &in, &out);
    291 		}
    292 
    293 		// Verify
    294 		{
    295 			const int	numValues	= (int)inputs.size();
    296 			const int	maxPrints	= 10;
    297 			int			numFailed	= 0;
    298 
    299 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    300 			{
    301 				const deInt16	in0			= (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
    302 				const deInt16	in1			= (deInt16)(deUint16)(inputs[valNdx] >> 16);
    303 				const float		ref0		= de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
    304 				const float		ref1		= de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
    305 				const float		res0		= outputs[valNdx].x();
    306 				const float		res1		= outputs[valNdx].y();
    307 
    308 				const deUint32	diff0	= getUlpDiff(ref0, res0);
    309 				const deUint32	diff1	= getUlpDiff(ref1, res1);
    310 
    311 				if (diff0 > maxDiff || diff1 > maxDiff)
    312 				{
    313 					if (numFailed < maxPrints)
    314 					{
    315 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
    316 															   << "  expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
    317 															   << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
    318 															   << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
    319 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    320 										   << TestLog::EndMessage;
    321 					}
    322 					else if (numFailed == maxPrints)
    323 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    324 
    325 					numFailed += 1;
    326 				}
    327 			}
    328 
    329 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    330 
    331 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    332 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    333 		}
    334 
    335 		return STOP;
    336 	}
    337 };
    338 
    339 class PackUnorm2x16Case : public ShaderPackingFunctionCase
    340 {
    341 public:
    342 	PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
    343 		: ShaderPackingFunctionCase	(context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
    344 		, m_precision				(precision)
    345 	{
    346 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
    347 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    348 
    349 		m_spec.source = "out0 = packUnorm2x16(in0);";
    350 	}
    351 
    352 	IterateResult iterate (void)
    353 	{
    354 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    355 		std::vector<tcu::Vec2>		inputs;
    356 		std::vector<deUint32>		outputs;
    357 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1		:		// Rounding only.
    358 												  m_precision == glu::PRECISION_MEDIUMP	? 65	:		// (2^-10) * (2^16) + 1
    359 												  m_precision == glu::PRECISION_LOWP	? 257	: 0;	// (2^-8) * (2^16) + 1
    360 
    361 		// Special values to check.
    362 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
    363 		inputs.push_back(tcu::Vec2(0.5f, 1.0f));
    364 		inputs.push_back(tcu::Vec2(1.0f, 0.5f));
    365 		inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
    366 		inputs.push_back(tcu::Vec2(0.25f, 0.75f));
    367 
    368 		// Random values, mostly in range.
    369 		for (int ndx = 0; ndx < 15; ndx++)
    370 		{
    371 			const float x = rnd.getFloat()*1.25f;
    372 			const float y = rnd.getFloat()*1.25f;
    373 			inputs.push_back(tcu::Vec2(x, y));
    374 		}
    375 
    376 		// Large random values.
    377 		for (int ndx = 0; ndx < 80; ndx++)
    378 		{
    379 			const float x = rnd.getFloat()*1e6f - 1e5f;
    380 			const float y = rnd.getFloat()*1e6f - 1e5f;
    381 			inputs.push_back(tcu::Vec2(x, y));
    382 		}
    383 
    384 		outputs.resize(inputs.size());
    385 
    386 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    387 
    388 		{
    389 			const void*	in	= &inputs[0];
    390 			void*		out	= &outputs[0];
    391 
    392 			m_executor->useProgram();
    393 			m_executor->execute((int)inputs.size(), &in, &out);
    394 		}
    395 
    396 		// Verify
    397 		{
    398 			const int	numValues	= (int)inputs.size();
    399 			const int	maxPrints	= 10;
    400 			int			numFailed	= 0;
    401 
    402 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    403 			{
    404 				const deUint16	ref0	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
    405 				const deUint16	ref1	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
    406 				const deUint32	ref		= (ref1 << 16) | ref0;
    407 				const deUint32	res		= outputs[valNdx];
    408 				const deUint16	res0	= (deUint16)(res & 0xffff);
    409 				const deUint16	res1	= (deUint16)(res >> 16);
    410 				const int		diff0	= de::abs((int)ref0 - (int)res0);
    411 				const int		diff1	= de::abs((int)ref1 - (int)res1);
    412 
    413 				if (diff0 > maxDiff || diff1 > maxDiff)
    414 				{
    415 					if (numFailed < maxPrints)
    416 					{
    417 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
    418 															   << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
    419 															   << ", got " << tcu::toHex(res)
    420 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    421 										   << TestLog::EndMessage;
    422 					}
    423 					else if (numFailed == maxPrints)
    424 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    425 
    426 					numFailed += 1;
    427 				}
    428 			}
    429 
    430 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    431 
    432 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    433 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    434 		}
    435 
    436 		return STOP;
    437 	}
    438 
    439 private:
    440 	glu::Precision m_precision;
    441 };
    442 
    443 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
    444 {
    445 public:
    446 	UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType)
    447 		: ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
    448 	{
    449 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    450 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
    451 
    452 		m_spec.source = "out0 = unpackUnorm2x16(in0);";
    453 	}
    454 
    455 	IterateResult iterate (void)
    456 	{
    457 		const deUint32				maxDiff		= 1; // Rounding error.
    458 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    459 		std::vector<deUint32>		inputs;
    460 		std::vector<tcu::Vec2>		outputs;
    461 
    462 		inputs.push_back(0x00000000u);
    463 		inputs.push_back(0x7fff8000u);
    464 		inputs.push_back(0x80007fffu);
    465 		inputs.push_back(0xffffffffu);
    466 		inputs.push_back(0x0001fffeu);
    467 
    468 		// Random values.
    469 		for (int ndx = 0; ndx < 95; ndx++)
    470 			inputs.push_back(rnd.getUint32());
    471 
    472 		outputs.resize(inputs.size());
    473 
    474 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    475 
    476 		{
    477 			const void*	in	= &inputs[0];
    478 			void*		out	= &outputs[0];
    479 
    480 			m_executor->useProgram();
    481 			m_executor->execute((int)inputs.size(), &in, &out);
    482 		}
    483 
    484 		// Verify
    485 		{
    486 			const int	numValues	= (int)inputs.size();
    487 			const int	maxPrints	= 10;
    488 			int			numFailed	= 0;
    489 
    490 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    491 			{
    492 				const deUint16	in0			= (deUint16)(inputs[valNdx] & 0xffff);
    493 				const deUint16	in1			= (deUint16)(inputs[valNdx] >> 16);
    494 				const float		ref0		= float(in0) / 65535.0f;
    495 				const float		ref1		= float(in1) / 65535.0f;
    496 				const float		res0		= outputs[valNdx].x();
    497 				const float		res1		= outputs[valNdx].y();
    498 
    499 				const deUint32	diff0		= getUlpDiff(ref0, res0);
    500 				const deUint32	diff1		= getUlpDiff(ref1, res1);
    501 
    502 				if (diff0 > maxDiff || diff1 > maxDiff)
    503 				{
    504 					if (numFailed < maxPrints)
    505 					{
    506 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
    507 															   << "  expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
    508 															   << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
    509 															   << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
    510 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    511 										   << TestLog::EndMessage;
    512 					}
    513 					else if (numFailed == maxPrints)
    514 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    515 
    516 					numFailed += 1;
    517 				}
    518 			}
    519 
    520 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    521 
    522 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    523 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    524 		}
    525 
    526 		return STOP;
    527 	}
    528 };
    529 
    530 class PackHalf2x16Case : public ShaderPackingFunctionCase
    531 {
    532 public:
    533 	PackHalf2x16Case (Context& context, glu::ShaderType shaderType)
    534 		: ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
    535 	{
    536 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
    537 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    538 
    539 		m_spec.source = "out0 = packHalf2x16(in0);";
    540 	}
    541 
    542 	IterateResult iterate (void)
    543 	{
    544 		const int					maxDiff		= 0; // Values can be represented exactly in mediump.
    545 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    546 		std::vector<tcu::Vec2>		inputs;
    547 		std::vector<deUint32>		outputs;
    548 
    549 		// Special values to check.
    550 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
    551 		inputs.push_back(tcu::Vec2(0.5f, 1.0f));
    552 		inputs.push_back(tcu::Vec2(1.0f, 0.5f));
    553 		inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
    554 		inputs.push_back(tcu::Vec2(0.25f, 0.75f));
    555 
    556 		// Random values.
    557 		{
    558 			const int	minExp	= -14;
    559 			const int	maxExp	= 15;
    560 
    561 			for (int ndx = 0; ndx < 95; ndx++)
    562 			{
    563 				tcu::Vec2 v;
    564 				for (int c = 0; c < 2; c++)
    565 				{
    566 					const int		s			= rnd.getBool() ? 1 : -1;
    567 					const int		exp			= rnd.getInt(minExp, maxExp);
    568 					const deUint32	mantissa	= rnd.getUint32() & ((1<<23)-1);
    569 
    570 					v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
    571 				}
    572 				inputs.push_back(v);
    573 			}
    574 		}
    575 
    576 		// Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
    577 		for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
    578 			*inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
    579 
    580 		outputs.resize(inputs.size());
    581 
    582 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    583 
    584 		{
    585 			const void*	in	= &inputs[0];
    586 			void*		out	= &outputs[0];
    587 
    588 			m_executor->useProgram();
    589 			m_executor->execute((int)inputs.size(), &in, &out);
    590 		}
    591 
    592 		// Verify
    593 		{
    594 			const int	numValues	= (int)inputs.size();
    595 			const int	maxPrints	= 10;
    596 			int			numFailed	= 0;
    597 
    598 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    599 			{
    600 				const deUint16	ref0	= (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
    601 				const deUint16	ref1	= (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
    602 				const deUint32	ref		= (ref1 << 16) | ref0;
    603 				const deUint32	res		= outputs[valNdx];
    604 				const deUint16	res0	= (deUint16)(res & 0xffff);
    605 				const deUint16	res1	= (deUint16)(res >> 16);
    606 				const int		diff0	= de::abs((int)ref0 - (int)res0);
    607 				const int		diff1	= de::abs((int)ref1 - (int)res1);
    608 
    609 				if (diff0 > maxDiff || diff1 > maxDiff)
    610 				{
    611 					if (numFailed < maxPrints)
    612 					{
    613 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
    614 															   << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
    615 															   << ", got " << tcu::toHex(res)
    616 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    617 										   << TestLog::EndMessage;
    618 					}
    619 					else if (numFailed == maxPrints)
    620 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    621 
    622 					numFailed += 1;
    623 				}
    624 			}
    625 
    626 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    627 
    628 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    629 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    630 		}
    631 
    632 		return STOP;
    633 	}
    634 };
    635 
    636 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
    637 {
    638 public:
    639 	UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType)
    640 		: ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
    641 	{
    642 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    643 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
    644 
    645 		m_spec.source = "out0 = unpackHalf2x16(in0);";
    646 	}
    647 
    648 	IterateResult iterate (void)
    649 	{
    650 		const int					maxDiff		= 0; // All bits must be accurate.
    651 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    652 		std::vector<deUint32>		inputs;
    653 		std::vector<tcu::Vec2>		outputs;
    654 
    655 		// Special values.
    656 		inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
    657 		inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
    658 		inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
    659 		inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
    660 
    661 		// Construct random values.
    662 		{
    663 			const int	minExp		= -14;
    664 			const int	maxExp		= 15;
    665 			const int	mantBits	= 10;
    666 
    667 			for (int ndx = 0; ndx < 96; ndx++)
    668 			{
    669 				deUint32 inVal = 0;
    670 				for (int c = 0; c < 2; c++)
    671 				{
    672 					const int		s			= rnd.getBool() ? 1 : -1;
    673 					const int		exp			= rnd.getInt(minExp, maxExp);
    674 					const deUint32	mantissa	= rnd.getUint32() & ((1<<mantBits)-1);
    675 					const deUint16	value		= tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (1u<<10) | mantissa).bits();
    676 
    677 					inVal |= value << (16*c);
    678 				}
    679 				inputs.push_back(inVal);
    680 			}
    681 		}
    682 
    683 		outputs.resize(inputs.size());
    684 
    685 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    686 
    687 		{
    688 			const void*	in	= &inputs[0];
    689 			void*		out	= &outputs[0];
    690 
    691 			m_executor->useProgram();
    692 			m_executor->execute((int)inputs.size(), &in, &out);
    693 		}
    694 
    695 		// Verify
    696 		{
    697 			const int	numValues	= (int)inputs.size();
    698 			const int	maxPrints	= 10;
    699 			int			numFailed	= 0;
    700 
    701 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    702 			{
    703 				const deUint16	in0			= (deUint16)(inputs[valNdx] & 0xffff);
    704 				const deUint16	in1			= (deUint16)(inputs[valNdx] >> 16);
    705 				const float		ref0		= tcu::Float16(in0).asFloat();
    706 				const float		ref1		= tcu::Float16(in1).asFloat();
    707 				const float		res0		= outputs[valNdx].x();
    708 				const float		res1		= outputs[valNdx].y();
    709 
    710 				const deUint32	refBits0	= tcu::Float32(ref0).bits();
    711 				const deUint32	refBits1	= tcu::Float32(ref1).bits();
    712 				const deUint32	resBits0	= tcu::Float32(res0).bits();
    713 				const deUint32	resBits1	= tcu::Float32(res1).bits();
    714 
    715 				const int		diff0	= de::abs((int)refBits0 - (int)resBits0);
    716 				const int		diff1	= de::abs((int)refBits1 - (int)resBits1);
    717 
    718 				if (diff0 > maxDiff || diff1 > maxDiff)
    719 				{
    720 					if (numFailed < maxPrints)
    721 					{
    722 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
    723 															   << "  expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
    724 															   << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
    725 															   << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
    726 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
    727 										   << TestLog::EndMessage;
    728 					}
    729 					else if (numFailed == maxPrints)
    730 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    731 
    732 					numFailed += 1;
    733 				}
    734 			}
    735 
    736 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    737 
    738 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    739 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    740 		}
    741 
    742 		return STOP;
    743 	}
    744 };
    745 
    746 class PackSnorm4x8Case : public ShaderPackingFunctionCase
    747 {
    748 public:
    749 	PackSnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
    750 		: ShaderPackingFunctionCase	(context, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
    751 		, m_precision				(precision)
    752 	{
    753 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
    754 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    755 
    756 		m_spec.source = "out0 = packSnorm4x8(in0);";
    757 	}
    758 
    759 	IterateResult iterate (void)
    760 	{
    761 		de::Random					rnd			(deStringHash(getName()) ^ 0x42f2c0);
    762 		std::vector<tcu::Vec4>		inputs;
    763 		std::vector<deUint32>		outputs;
    764 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1	:		// Rounding only.
    765 												  m_precision == glu::PRECISION_MEDIUMP	? 1	:		// (2^-10) * (2^7) + 1
    766 												  m_precision == glu::PRECISION_LOWP	? 2	: 0;	// (2^-8) * (2^7) + 1
    767 
    768 		// Special values to check.
    769 		inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
    770 		inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
    771 		inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
    772 		inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
    773 		inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
    774 
    775 		// Random values, mostly in range.
    776 		for (int ndx = 0; ndx < 15; ndx++)
    777 		{
    778 			const float x = rnd.getFloat()*2.5f - 1.25f;
    779 			const float y = rnd.getFloat()*2.5f - 1.25f;
    780 			const float z = rnd.getFloat()*2.5f - 1.25f;
    781 			const float w = rnd.getFloat()*2.5f - 1.25f;
    782 			inputs.push_back(tcu::Vec4(x, y, z, w));
    783 		}
    784 
    785 		// Large random values.
    786 		for (int ndx = 0; ndx < 80; ndx++)
    787 		{
    788 			const float x = rnd.getFloat()*1e6f - 0.5e6f;
    789 			const float y = rnd.getFloat()*1e6f - 0.5e6f;
    790 			const float z = rnd.getFloat()*1e6f - 0.5e6f;
    791 			const float w = rnd.getFloat()*1e6f - 0.5e6f;
    792 			inputs.push_back(tcu::Vec4(x, y, z, w));
    793 		}
    794 
    795 		outputs.resize(inputs.size());
    796 
    797 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    798 
    799 		{
    800 			const void*	in	= &inputs[0];
    801 			void*		out	= &outputs[0];
    802 
    803 			m_executor->useProgram();
    804 			m_executor->execute((int)inputs.size(), &in, &out);
    805 		}
    806 
    807 		// Verify
    808 		{
    809 			const int	numValues	= (int)inputs.size();
    810 			const int	maxPrints	= 10;
    811 			int			numFailed	= 0;
    812 
    813 			for (int valNdx = 0; valNdx < numValues; valNdx++)
    814 			{
    815 				const deUint16	ref0	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
    816 				const deUint16	ref1	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
    817 				const deUint16	ref2	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
    818 				const deUint16	ref3	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
    819 				const deUint32	ref		= (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
    820 				const deUint32	res		= outputs[valNdx];
    821 				const deUint16	res0	= (deUint8)(res & 0xff);
    822 				const deUint16	res1	= (deUint8)((res >> 8) & 0xff);
    823 				const deUint16	res2	= (deUint8)((res >> 16) & 0xff);
    824 				const deUint16	res3	= (deUint8)((res >> 24) & 0xff);
    825 				const int		diff0	= de::abs((int)ref0 - (int)res0);
    826 				const int		diff1	= de::abs((int)ref1 - (int)res1);
    827 				const int		diff2	= de::abs((int)ref2 - (int)res2);
    828 				const int		diff3	= de::abs((int)ref3 - (int)res3);
    829 
    830 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
    831 				{
    832 					if (numFailed < maxPrints)
    833 					{
    834 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
    835 															   << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
    836 															   << ", got " << tcu::toHex(res)
    837 															   << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
    838 										   << TestLog::EndMessage;
    839 					}
    840 					else if (numFailed == maxPrints)
    841 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    842 
    843 					numFailed += 1;
    844 				}
    845 			}
    846 
    847 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    848 
    849 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    850 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    851 		}
    852 
    853 		return STOP;
    854 	}
    855 
    856 private:
    857 	glu::Precision m_precision;
    858 };
    859 
    860 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
    861 {
    862 public:
    863 	UnpackSnorm4x8Case (Context& context, glu::ShaderType shaderType)
    864 		: ShaderPackingFunctionCase(context, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
    865 	{
    866 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    867 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
    868 
    869 		m_spec.source = "out0 = unpackSnorm4x8(in0);";
    870 	}
    871 
    872 	IterateResult iterate (void)
    873 	{
    874 		const deUint32				maxDiff		= 1; // Rounding error.
    875 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    876 		std::vector<deUint32>		inputs;
    877 		std::vector<tcu::Vec4>		outputs;
    878 
    879 		inputs.push_back(0x00000000u);
    880 		inputs.push_back(0x7fff8000u);
    881 		inputs.push_back(0x80007fffu);
    882 		inputs.push_back(0xffffffffu);
    883 		inputs.push_back(0x0001fffeu);
    884 
    885 		// Random values.
    886 		for (int ndx = 0; ndx < 95; ndx++)
    887 			inputs.push_back(rnd.getUint32());
    888 
    889 		outputs.resize(inputs.size());
    890 
    891 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
    892 
    893 		{
    894 			const void*	in	= &inputs[0];
    895 			void*		out	= &outputs[0];
    896 
    897 			m_executor->useProgram();
    898 			m_executor->execute((int)inputs.size(), &in, &out);
    899 		}
    900 
    901 		// Verify
    902 		{
    903 			const int	numValues	= (int)inputs.size();
    904 			const int	maxPrints	= 10;
    905 			int			numFailed	= 0;
    906 
    907 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
    908 			{
    909 				const deInt8	in0		= (deInt8)(deUint8)(inputs[valNdx] & 0xff);
    910 				const deInt8	in1		= (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
    911 				const deInt8	in2		= (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
    912 				const deInt8	in3		= (deInt8)(deUint8)(inputs[valNdx] >> 24);
    913 				const float		ref0	= de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
    914 				const float		ref1	= de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
    915 				const float		ref2	= de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
    916 				const float		ref3	= de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
    917 				const float		res0	= outputs[valNdx].x();
    918 				const float		res1	= outputs[valNdx].y();
    919 				const float		res2	= outputs[valNdx].z();
    920 				const float		res3	= outputs[valNdx].w();
    921 
    922 				const deUint32	diff0	= getUlpDiff(ref0, res0);
    923 				const deUint32	diff1	= getUlpDiff(ref1, res1);
    924 				const deUint32	diff2	= getUlpDiff(ref2, res2);
    925 				const deUint32	diff3	= getUlpDiff(ref3, res3);
    926 
    927 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
    928 				{
    929 					if (numFailed < maxPrints)
    930 					{
    931 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
    932 															   << "  expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
    933 															   << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
    934 															   << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
    935 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
    936 										   << TestLog::EndMessage;
    937 					}
    938 					else if (numFailed == maxPrints)
    939 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    940 
    941 					numFailed += 1;
    942 				}
    943 			}
    944 
    945 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
    946 
    947 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    948 									numFailed == 0 ? "Pass"					: "Result comparison failed");
    949 		}
    950 
    951 		return STOP;
    952 	}
    953 };
    954 
    955 class PackUnorm4x8Case : public ShaderPackingFunctionCase
    956 {
    957 public:
    958 	PackUnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
    959 		: ShaderPackingFunctionCase	(context, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
    960 		, m_precision				(precision)
    961 	{
    962 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
    963 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
    964 
    965 		m_spec.source = "out0 = packUnorm4x8(in0);";
    966 	}
    967 
    968 	IterateResult iterate (void)
    969 	{
    970 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
    971 		std::vector<tcu::Vec4>		inputs;
    972 		std::vector<deUint32>		outputs;
    973 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1	:		// Rounding only.
    974 												  m_precision == glu::PRECISION_MEDIUMP	? 1	:		// (2^-10) * (2^8) + 1
    975 												  m_precision == glu::PRECISION_LOWP	? 2	: 0;	// (2^-8) * (2^8) + 1
    976 
    977 		// Special values to check.
    978 		inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
    979 		inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
    980 		inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
    981 		inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
    982 		inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
    983 
    984 		// Random values, mostly in range.
    985 		for (int ndx = 0; ndx < 15; ndx++)
    986 		{
    987 			const float x = rnd.getFloat()*1.25f - 0.125f;
    988 			const float y = rnd.getFloat()*1.25f - 0.125f;
    989 			const float z = rnd.getFloat()*1.25f - 0.125f;
    990 			const float w = rnd.getFloat()*1.25f - 0.125f;
    991 			inputs.push_back(tcu::Vec4(x, y, z, w));
    992 		}
    993 
    994 		// Large random values.
    995 		for (int ndx = 0; ndx < 80; ndx++)
    996 		{
    997 			const float x = rnd.getFloat()*1e6f - 1e5f;
    998 			const float y = rnd.getFloat()*1e6f - 1e5f;
    999 			const float z = rnd.getFloat()*1e6f - 1e5f;
   1000 			const float w = rnd.getFloat()*1e6f - 1e5f;
   1001 			inputs.push_back(tcu::Vec4(x, y, z, w));
   1002 		}
   1003 
   1004 		outputs.resize(inputs.size());
   1005 
   1006 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
   1007 
   1008 		{
   1009 			const void*	in	= &inputs[0];
   1010 			void*		out	= &outputs[0];
   1011 
   1012 			m_executor->useProgram();
   1013 			m_executor->execute((int)inputs.size(), &in, &out);
   1014 		}
   1015 
   1016 		// Verify
   1017 		{
   1018 			const int	numValues	= (int)inputs.size();
   1019 			const int	maxPrints	= 10;
   1020 			int			numFailed	= 0;
   1021 
   1022 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
   1023 			{
   1024 				const deUint16	ref0	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
   1025 				const deUint16	ref1	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
   1026 				const deUint16	ref2	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
   1027 				const deUint16	ref3	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
   1028 				const deUint32	ref		= (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
   1029 				const deUint32	res		= outputs[valNdx];
   1030 				const deUint16	res0	= (deUint8)(res & 0xff);
   1031 				const deUint16	res1	= (deUint8)((res >> 8) & 0xff);
   1032 				const deUint16	res2	= (deUint8)((res >> 16) & 0xff);
   1033 				const deUint16	res3	= (deUint8)((res >> 24) & 0xff);
   1034 				const int		diff0	= de::abs((int)ref0 - (int)res0);
   1035 				const int		diff1	= de::abs((int)ref1 - (int)res1);
   1036 				const int		diff2	= de::abs((int)ref2 - (int)res2);
   1037 				const int		diff3	= de::abs((int)ref3 - (int)res3);
   1038 
   1039 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
   1040 				{
   1041 					if (numFailed < maxPrints)
   1042 					{
   1043 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
   1044 															   << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
   1045 															   << ", got " << tcu::toHex(res)
   1046 															   << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
   1047 										   << TestLog::EndMessage;
   1048 					}
   1049 					else if (numFailed == maxPrints)
   1050 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
   1051 
   1052 					numFailed += 1;
   1053 				}
   1054 			}
   1055 
   1056 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
   1057 
   1058 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
   1059 									numFailed == 0 ? "Pass"					: "Result comparison failed");
   1060 		}
   1061 
   1062 		return STOP;
   1063 	}
   1064 
   1065 private:
   1066 	glu::Precision m_precision;
   1067 };
   1068 
   1069 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
   1070 {
   1071 public:
   1072 	UnpackUnorm4x8Case (Context& context, glu::ShaderType shaderType)
   1073 		: ShaderPackingFunctionCase(context, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
   1074 	{
   1075 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
   1076 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1077 
   1078 		m_spec.source = "out0 = unpackUnorm4x8(in0);";
   1079 	}
   1080 
   1081 	IterateResult iterate (void)
   1082 	{
   1083 		const deUint32				maxDiff		= 1; // Rounding error.
   1084 		de::Random					rnd			(deStringHash(getName()) ^ 0x776002);
   1085 		std::vector<deUint32>		inputs;
   1086 		std::vector<tcu::Vec4>		outputs;
   1087 
   1088 		inputs.push_back(0x00000000u);
   1089 		inputs.push_back(0x7fff8000u);
   1090 		inputs.push_back(0x80007fffu);
   1091 		inputs.push_back(0xffffffffu);
   1092 		inputs.push_back(0x0001fffeu);
   1093 
   1094 		// Random values.
   1095 		for (int ndx = 0; ndx < 95; ndx++)
   1096 			inputs.push_back(rnd.getUint32());
   1097 
   1098 		outputs.resize(inputs.size());
   1099 
   1100 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
   1101 
   1102 		{
   1103 			const void*	in	= &inputs[0];
   1104 			void*		out	= &outputs[0];
   1105 
   1106 			m_executor->useProgram();
   1107 			m_executor->execute((int)inputs.size(), &in, &out);
   1108 		}
   1109 
   1110 		// Verify
   1111 		{
   1112 			const int	numValues	= (int)inputs.size();
   1113 			const int	maxPrints	= 10;
   1114 			int			numFailed	= 0;
   1115 
   1116 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
   1117 			{
   1118 				const deUint8	in0		= (deUint8)(inputs[valNdx] & 0xff);
   1119 				const deUint8	in1		= (deUint8)((inputs[valNdx] >> 8) & 0xff);
   1120 				const deUint8	in2		= (deUint8)((inputs[valNdx] >> 16) & 0xff);
   1121 				const deUint8	in3		= (deUint8)(inputs[valNdx] >> 24);
   1122 				const float		ref0	= de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
   1123 				const float		ref1	= de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
   1124 				const float		ref2	= de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
   1125 				const float		ref3	= de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
   1126 				const float		res0	= outputs[valNdx].x();
   1127 				const float		res1	= outputs[valNdx].y();
   1128 				const float		res2	= outputs[valNdx].z();
   1129 				const float		res3	= outputs[valNdx].w();
   1130 
   1131 				const deUint32	diff0	= getUlpDiff(ref0, res0);
   1132 				const deUint32	diff1	= getUlpDiff(ref1, res1);
   1133 				const deUint32	diff2	= getUlpDiff(ref2, res2);
   1134 				const deUint32	diff3	= getUlpDiff(ref3, res3);
   1135 
   1136 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
   1137 				{
   1138 					if (numFailed < maxPrints)
   1139 					{
   1140 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
   1141 															   << "  expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
   1142 															   << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
   1143 															   << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
   1144 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
   1145 										   << TestLog::EndMessage;
   1146 					}
   1147 					else if (numFailed == maxPrints)
   1148 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
   1149 
   1150 					numFailed += 1;
   1151 				}
   1152 			}
   1153 
   1154 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
   1155 
   1156 			m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
   1157 									numFailed == 0 ? "Pass"					: "Result comparison failed");
   1158 		}
   1159 
   1160 		return STOP;
   1161 	}
   1162 };
   1163 
   1164 ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
   1165 	: TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
   1166 {
   1167 }
   1168 
   1169 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
   1170 {
   1171 }
   1172 
   1173 void ShaderPackingFunctionTests::init (void)
   1174 {
   1175 	// New built-in functions in GLES 3.1
   1176 	{
   1177 		const glu::ShaderType allShaderTypes[] =
   1178 		{
   1179 			glu::SHADERTYPE_VERTEX,
   1180 			glu::SHADERTYPE_TESSELLATION_CONTROL,
   1181 			glu::SHADERTYPE_TESSELLATION_EVALUATION,
   1182 			glu::SHADERTYPE_GEOMETRY,
   1183 			glu::SHADERTYPE_FRAGMENT,
   1184 			glu::SHADERTYPE_COMPUTE
   1185 		};
   1186 
   1187 		// packSnorm4x8
   1188 		for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
   1189 		{
   1190 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
   1191 				addChild(new PackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
   1192 		}
   1193 
   1194 		// unpackSnorm4x8
   1195 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
   1196 			addChild(new UnpackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
   1197 
   1198 		// packUnorm4x8
   1199 		for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
   1200 		{
   1201 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
   1202 				addChild(new PackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
   1203 		}
   1204 
   1205 		// unpackUnorm4x8
   1206 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
   1207 			addChild(new UnpackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
   1208 	}
   1209 
   1210 	// GLES 3 functions in new shader types.
   1211 	{
   1212 		const glu::ShaderType newShaderTypes[] =
   1213 		{
   1214 			glu::SHADERTYPE_GEOMETRY,
   1215 			glu::SHADERTYPE_COMPUTE
   1216 		};
   1217 
   1218 		// packSnorm2x16
   1219 		for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
   1220 		{
   1221 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1222 				addChild(new PackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
   1223 		}
   1224 
   1225 		// unpackSnorm2x16
   1226 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1227 			addChild(new UnpackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
   1228 
   1229 		// packUnorm2x16
   1230 		for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
   1231 		{
   1232 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1233 				addChild(new PackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
   1234 		}
   1235 
   1236 		// unpackUnorm2x16
   1237 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1238 			addChild(new UnpackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
   1239 
   1240 		// packHalf2x16
   1241 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1242 			addChild(new PackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
   1243 
   1244 		// unpackHalf2x16
   1245 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
   1246 			addChild(new UnpackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
   1247 	}
   1248 }
   1249 
   1250 } // Functional
   1251 } // gles31
   1252 } // deqp
   1253