• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getUlpDiff(float a,float b)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;
HexFloatdeqp::gles31::Functional::__anond3ac8cb10111::HexFloat57 	HexFloat (const float value_) : value(value_) {}
58 };
59 
operator <<(std::ostream & str,const HexFloat & v)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 
ShaderPackingFunctionCase(Context & context,const char * name,const char * description,glu::ShaderType shaderType)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 
~ShaderPackingFunctionCase(void)96 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
97 {
98 	ShaderPackingFunctionCase::deinit();
99 }
100 
init(void)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 
deinit(void)112 void ShaderPackingFunctionCase::deinit (void)
113 {
114 	delete m_executor;
115 	m_executor = DE_NULL;
116 }
117 
118 // Test cases
119 
getPrecisionPostfix(glu::Precision precision)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 
getShaderTypePostfix(glu::ShaderType shaderType)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:
PackSnorm2x16Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)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 
iterate(void)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:
UnpackSnorm2x16Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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:
PackUnorm2x16Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)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 
iterate(void)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:
UnpackUnorm2x16Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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:
PackHalf2x16Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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:
UnpackHalf2x16Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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 */, (deUint16)((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:
PackSnorm4x8Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)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 
iterate(void)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:
UnpackSnorm4x8Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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:
PackUnorm4x8Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)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 
iterate(void)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:
UnpackUnorm4x8Case(Context & context,glu::ShaderType shaderType)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 
iterate(void)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 
ShaderPackingFunctionTests(Context & context)1164 ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
1165 	: TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
1166 {
1167 }
1168 
~ShaderPackingFunctionTests(void)1169 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1170 {
1171 }
1172 
init(void)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