• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Floating-point packing and unpacking function tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderPackingFunctionTests.hpp"
27 #include "vktShaderExecutor.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuFormatUtil.hpp"
30 #include "tcuFloat.hpp"
31 #include "tcuVectorUtil.hpp"
32 #include "deRandom.hpp"
33 #include "deMath.h"
34 #include "deString.h"
35 #include "deSharedPtr.hpp"
36 
37 namespace vkt
38 {
39 namespace shaderexecutor
40 {
41 
42 using namespace shaderexecutor;
43 
44 using std::string;
45 using tcu::TestLog;
46 
47 namespace
48 {
49 
getUlpDiff(float a,float b)50 inline deUint32 getUlpDiff (float a, float b)
51 {
52 	const deUint32	aBits	= tcu::Float32(a).bits();
53 	const deUint32	bBits	= tcu::Float32(b).bits();
54 	return aBits > bBits ? aBits - bBits : bBits - aBits;
55 }
56 
57 struct HexFloat
58 {
59 	const float value;
HexFloatvkt::shaderexecutor::__anon2396bd750111::HexFloat60 	HexFloat (const float value_) : value(value_) {}
61 };
62 
operator <<(std::ostream & str,const HexFloat & v)63 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
64 {
65 	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
66 }
67 
68 } // anonymous
69 
70 // ShaderPackingFunctionCase
71 
72 class ShaderPackingFunctionCase : public TestCase
73 {
74 public:
75 										ShaderPackingFunctionCase			(tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
76 										~ShaderPackingFunctionCase			(void);
77 
78 			void						checkSupport						(Context& context) const;
initPrograms(vk::SourceCollections & programCollection) const79 	virtual	void						initPrograms						(vk::SourceCollections& programCollection) const
80 										{
81 											generateSources(m_shaderType, m_spec, programCollection);
82 										}
83 
84 protected:
85 	const glu::ShaderType				m_shaderType;
86 	ShaderSpec							m_spec;
87 
88 private:
89 										ShaderPackingFunctionCase			(const ShaderPackingFunctionCase& other);
90 	ShaderPackingFunctionCase&			operator=							(const ShaderPackingFunctionCase& other);
91 };
92 
ShaderPackingFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ShaderType shaderType)93 ShaderPackingFunctionCase::ShaderPackingFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
94 	: TestCase		(testCtx, name, description)
95 	, m_shaderType	(shaderType)
96 {
97 }
98 
~ShaderPackingFunctionCase(void)99 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
100 {
101 }
102 
checkSupport(Context & context) const103 void ShaderPackingFunctionCase::checkSupport (Context& context) const
104 {
105 	checkSupportShader(context, m_shaderType);
106 }
107 
108 // ShaderPackingFunctionTestInstance
109 
110 class ShaderPackingFunctionTestInstance : public TestInstance
111 {
112 public:
ShaderPackingFunctionTestInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)113 										ShaderPackingFunctionTestInstance	(Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
114 											: TestInstance	(context)
115 											, m_testCtx		(context.getTestContext())
116 											, m_shaderType	(shaderType)
117 											, m_spec		(spec)
118 											, m_name		(name)
119 											, m_executor	(createExecutor(context, m_shaderType, m_spec))
120 										{
121 										}
122 	virtual tcu::TestStatus				iterate								(void) = 0;
123 protected:
124 	tcu::TestContext&					m_testCtx;
125 	const glu::ShaderType				m_shaderType;
126 	ShaderSpec							m_spec;
127 	const char*							m_name;
128 	de::UniquePtr<ShaderExecutor>		m_executor;
129 };
130 
131 // Test cases
132 
133 class PackSnorm2x16CaseInstance: public ShaderPackingFunctionTestInstance
134 {
135 public:
PackSnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)136 	PackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
137 		: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
138 		, m_precision						(precision)
139 	{
140 	}
141 
iterate(void)142 	tcu::TestStatus iterate (void)
143 	{
144 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
145 		std::vector<tcu::Vec2>		inputs;
146 		std::vector<deUint32>		outputs;
147 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1		:		// Rounding only.
148 												  m_precision == glu::PRECISION_MEDIUMP	? 33	:		// (2^-10) * (2^15) + 1
149 												  m_precision == glu::PRECISION_LOWP	? 129	: 0;	// (2^-8) * (2^15) + 1
150 
151 		// Special values to check.
152 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
153 		inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
154 		inputs.push_back(tcu::Vec2(0.5f, -0.5f));
155 		inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
156 		inputs.push_back(tcu::Vec2(0.25f, -0.75f));
157 
158 		// Random values, mostly in range.
159 		for (int ndx = 0; ndx < 15; ndx++)
160 		{
161 			inputs.push_back(tcu::randomVector<float, 2>(rnd, tcu::Vec2(-1.25f), tcu::Vec2(1.25f)));
162 		}
163 
164 		// Large random values.
165 		for (int ndx = 0; ndx < 80; ndx++)
166 		{
167 			inputs.push_back(tcu::randomVector<float, 2>(rnd, tcu::Vec2(-0.5e6f), tcu::Vec2(0.5e6f)));
168 		}
169 
170 		outputs.resize(inputs.size());
171 
172 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
173 
174 		{
175 			const void*	in	= &inputs[0];
176 			void*		out	= &outputs[0];
177 
178 			m_executor->execute((int)inputs.size(), &in, &out);
179 		}
180 
181 		// Verify
182 		{
183 			const int	numValues	= (int)inputs.size();
184 			const int	maxPrints	= 10;
185 			int			numFailed	= 0;
186 
187 			for (int valNdx = 0; valNdx < numValues; valNdx++)
188 			{
189 				const deUint16	ref0	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
190 				const deUint16	ref1	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
191 				const deUint32	ref		= (ref1 << 16) | ref0;
192 				const deUint32	res		= outputs[valNdx];
193 				const deUint16	res0	= (deUint16)(res & 0xffff);
194 				const deUint16	res1	= (deUint16)(res >> 16);
195 				const int		diff0	= de::abs((int)ref0 - (int)res0);
196 				const int		diff1	= de::abs((int)ref1 - (int)res1);
197 
198 				if (diff0 > maxDiff || diff1 > maxDiff)
199 				{
200 					if (numFailed < maxPrints)
201 					{
202 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
203 															   << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
204 															   << ", got " << tcu::toHex(res)
205 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
206 										   << TestLog::EndMessage;
207 					}
208 					else if (numFailed == maxPrints)
209 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
210 
211 					numFailed += 1;
212 				}
213 			}
214 
215 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
216 
217 			if (numFailed == 0)
218 				return tcu::TestStatus::pass("Pass");
219 			else
220 				return tcu::TestStatus::fail("Result comparison failed");
221 
222 		}
223 	}
224 
225 private:
226 	const glu::Precision m_precision;
227 };
228 
229 class PackSnorm2x16Case : public ShaderPackingFunctionCase
230 {
231 public:
PackSnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)232 	PackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
233 		: ShaderPackingFunctionCase	(testCtx, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
234 		, m_precision				(precision)
235 	{
236 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
237 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
238 
239 		m_spec.source = "out0 = packSnorm2x16(in0);";
240 	}
241 
createInstance(Context & ctx) const242 	TestInstance* createInstance (Context& ctx) const
243 	{
244 		return new PackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
245 	}
246 
247 private:
248 	const glu::Precision m_precision;
249 };
250 
251 class UnpackSnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
252 {
253 public:
UnpackSnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)254 	UnpackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
255 	: ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
256 	{
257 	}
258 
iterate(void)259 	tcu::TestStatus iterate (void)
260 	{
261 		const deUint32				maxDiff		= 1; // Rounding error.
262 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
263 		std::vector<deUint32>		inputs;
264 		std::vector<tcu::Vec2>		outputs;
265 
266 		inputs.push_back(0x00000000u);
267 		inputs.push_back(0x7fff8000u);
268 		inputs.push_back(0x80007fffu);
269 		inputs.push_back(0xffffffffu);
270 		inputs.push_back(0x0001fffeu);
271 
272 		// Random values.
273 		for (int ndx = 0; ndx < 95; ndx++)
274 			inputs.push_back(rnd.getUint32());
275 
276 		outputs.resize(inputs.size());
277 
278 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
279 
280 		{
281 			const void*	in	= &inputs[0];
282 			void*		out	= &outputs[0];
283 
284 			m_executor->execute((int)inputs.size(), &in, &out);
285 		}
286 
287 		// Verify
288 		{
289 			const int	numValues	= (int)inputs.size();
290 			const int	maxPrints	= 10;
291 			int			numFailed	= 0;
292 
293 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
294 			{
295 				const deInt16	in0			= (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
296 				const deInt16	in1			= (deInt16)(deUint16)(inputs[valNdx] >> 16);
297 				const float		ref0		= de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
298 				const float		ref1		= de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
299 				const float		res0		= outputs[valNdx].x();
300 				const float		res1		= outputs[valNdx].y();
301 
302 				const deUint32	diff0	= getUlpDiff(ref0, res0);
303 				const deUint32	diff1	= getUlpDiff(ref1, res1);
304 
305 				if (diff0 > maxDiff || diff1 > maxDiff)
306 				{
307 					if (numFailed < maxPrints)
308 					{
309 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
310 															   << "  expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
311 															   << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
312 															   << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
313 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
314 										   << TestLog::EndMessage;
315 					}
316 					else if (numFailed == maxPrints)
317 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
318 
319 					numFailed += 1;
320 				}
321 			}
322 
323 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
324 
325 			if (numFailed == 0)
326 				return tcu::TestStatus::pass("Pass");
327 			else
328 				return tcu::TestStatus::fail("Result comparison failed");
329 
330 		}
331 	}
332 };
333 
334 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
335 {
336 public:
UnpackSnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)337 	UnpackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
338 		: ShaderPackingFunctionCase	(testCtx, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
339 	{
340 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
341 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
342 
343 		m_spec.source = "out0 = unpackSnorm2x16(in0);";
344 	}
345 
createInstance(Context & ctx) const346 	TestInstance* createInstance (Context& ctx) const
347 	{
348 		return new UnpackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
349 	}
350 };
351 
352 class PackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
353 {
354 public:
PackUnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)355 	PackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
356 	: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
357 	, m_precision						(precision)
358 	{
359 	}
360 
iterate(void)361 	tcu::TestStatus iterate (void)
362 	{
363 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
364 		std::vector<tcu::Vec2>		inputs;
365 		std::vector<deUint32>		outputs;
366 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1		:		// Rounding only.
367 												  m_precision == glu::PRECISION_MEDIUMP	? 65	:		// (2^-10) * (2^16) + 1
368 												  m_precision == glu::PRECISION_LOWP	? 257	: 0;	// (2^-8) * (2^16) + 1
369 
370 		// Special values to check.
371 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
372 		inputs.push_back(tcu::Vec2(0.5f, 1.0f));
373 		inputs.push_back(tcu::Vec2(1.0f, 0.5f));
374 		inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
375 		inputs.push_back(tcu::Vec2(0.25f, 0.75f));
376 
377 		// Random values, mostly in range.
378 		for (int ndx = 0; ndx < 15; ndx++)
379 		{
380 			inputs.push_back(tcu::randomVector<float, 2>(rnd, tcu::Vec2(0.0f), tcu::Vec2(1.25f)));
381 		}
382 
383 		// Large random values.
384 		for (int ndx = 0; ndx < 80; ndx++)
385 		{
386 			inputs.push_back(tcu::randomVector<float, 2>(rnd, tcu::Vec2(-1e5f), tcu::Vec2(0.9e6f)));
387 		}
388 
389 		outputs.resize(inputs.size());
390 
391 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
392 
393 		{
394 			const void*	in	= &inputs[0];
395 			void*		out	= &outputs[0];
396 
397 			m_executor->execute((int)inputs.size(), &in, &out);
398 		}
399 
400 		// Verify
401 		{
402 			const int	numValues	= (int)inputs.size();
403 			const int	maxPrints	= 10;
404 			int			numFailed	= 0;
405 
406 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
407 			{
408 				const deUint16	ref0	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
409 				const deUint16	ref1	= (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
410 				const deUint32	ref		= (ref1 << 16) | ref0;
411 				const deUint32	res		= outputs[valNdx];
412 				const deUint16	res0	= (deUint16)(res & 0xffff);
413 				const deUint16	res1	= (deUint16)(res >> 16);
414 				const int		diff0	= de::abs((int)ref0 - (int)res0);
415 				const int		diff1	= de::abs((int)ref1 - (int)res1);
416 
417 				if (diff0 > maxDiff || diff1 > maxDiff)
418 				{
419 					if (numFailed < maxPrints)
420 					{
421 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
422 															   << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
423 															   << ", got " << tcu::toHex(res)
424 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
425 										   << TestLog::EndMessage;
426 					}
427 					else if (numFailed == maxPrints)
428 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
429 
430 					numFailed += 1;
431 				}
432 			}
433 
434 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
435 
436 			if (numFailed == 0)
437 				return tcu::TestStatus::pass("Pass");
438 			else
439 				return tcu::TestStatus::fail("Result comparison failed");
440 
441 		}
442 	}
443 
444 private:
445 	const glu::Precision m_precision;
446 };
447 
448 class PackUnorm2x16Case : public ShaderPackingFunctionCase
449 {
450 public:
PackUnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)451 	PackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
452 		: ShaderPackingFunctionCase	(testCtx, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
453 		, m_precision				(precision)
454 	{
455 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
456 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
457 
458 		m_spec.source = "out0 = packUnorm2x16(in0);";
459 	}
460 
createInstance(Context & ctx) const461 	TestInstance* createInstance (Context& ctx) const
462 	{
463 		return new PackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
464 	}
465 
466 private:
467 	const glu::Precision m_precision;
468 };
469 
470 class UnpackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
471 {
472 public:
UnpackUnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)473 	UnpackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
474 		: ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
475 	{
476 	}
477 
iterate(void)478 	tcu::TestStatus iterate (void)
479 	{
480 		const deUint32				maxDiff		= 1; // Rounding error.
481 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
482 		std::vector<deUint32>		inputs;
483 		std::vector<tcu::Vec2>		outputs;
484 
485 		inputs.push_back(0x00000000u);
486 		inputs.push_back(0x7fff8000u);
487 		inputs.push_back(0x80007fffu);
488 		inputs.push_back(0xffffffffu);
489 		inputs.push_back(0x0001fffeu);
490 
491 		// Random values.
492 		for (int ndx = 0; ndx < 95; ndx++)
493 			inputs.push_back(rnd.getUint32());
494 
495 		outputs.resize(inputs.size());
496 
497 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
498 
499 		{
500 			const void*	in	= &inputs[0];
501 			void*		out	= &outputs[0];
502 
503 			m_executor->execute((int)inputs.size(), &in, &out);
504 		}
505 
506 		// Verify
507 		{
508 			const int	numValues	= (int)inputs.size();
509 			const int	maxPrints	= 10;
510 			int			numFailed	= 0;
511 
512 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
513 			{
514 				const deUint16	in0			= (deUint16)(inputs[valNdx] & 0xffff);
515 				const deUint16	in1			= (deUint16)(inputs[valNdx] >> 16);
516 				const float		ref0		= float(in0) / 65535.0f;
517 				const float		ref1		= float(in1) / 65535.0f;
518 				const float		res0		= outputs[valNdx].x();
519 				const float		res1		= outputs[valNdx].y();
520 
521 				const deUint32	diff0		= getUlpDiff(ref0, res0);
522 				const deUint32	diff1		= getUlpDiff(ref1, res1);
523 
524 				if (diff0 > maxDiff || diff1 > maxDiff)
525 				{
526 					if (numFailed < maxPrints)
527 					{
528 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
529 															   << "  expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
530 															   << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
531 															   << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
532 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
533 										   << TestLog::EndMessage;
534 					}
535 					else if (numFailed == maxPrints)
536 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
537 
538 					numFailed += 1;
539 				}
540 			}
541 
542 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
543 
544 			if (numFailed == 0)
545 				return tcu::TestStatus::pass("Pass");
546 			else
547 				return tcu::TestStatus::fail("Result comparison failed");
548 
549 		}
550 	}
551 };
552 
553 
554 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
555 {
556 public:
UnpackUnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)557 	UnpackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
558 		: ShaderPackingFunctionCase(testCtx, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
559 	{
560 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
561 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
562 
563 		m_spec.source = "out0 = unpackUnorm2x16(in0);";
564 	}
565 
createInstance(Context & ctx) const566 	TestInstance* createInstance (Context& ctx) const
567 	{
568 		return new UnpackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
569 	}
570 
571 };
572 
573 class PackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
574 {
575 public:
PackHalf2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)576 	PackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
577 	: ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
578 	{
579 	}
580 
iterate(void)581 	tcu::TestStatus iterate (void)
582 	{
583 		const int					maxDiff		= 0; // Values can be represented exactly in mediump.
584 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
585 		std::vector<tcu::Vec2>		inputs;
586 		std::vector<deUint32>		outputs;
587 
588 		// Special values to check.
589 		inputs.push_back(tcu::Vec2(0.0f, 0.0f));
590 		inputs.push_back(tcu::Vec2(0.5f, 1.0f));
591 		inputs.push_back(tcu::Vec2(1.0f, 0.5f));
592 		inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
593 		inputs.push_back(tcu::Vec2(0.25f, 0.75f));
594 
595 		// Random values.
596 		{
597 			const int	minExp	= -14;
598 			const int	maxExp	= 15;
599 
600 			for (int ndx = 0; ndx < 95; ndx++)
601 			{
602 				tcu::Vec2 v;
603 				for (int c = 0; c < 2; c++)
604 				{
605 					const int		s			= rnd.getBool() ? 1 : -1;
606 					const int		exp			= rnd.getInt(minExp, maxExp);
607 					const deUint32	mantissa	= rnd.getUint32() & ((1<<23)-1);
608 
609 					v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
610 				}
611 				inputs.push_back(v);
612 			}
613 		}
614 
615 		// Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
616 		for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
617 			*inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
618 
619 		outputs.resize(inputs.size());
620 
621 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
622 
623 		{
624 			const void*	in	= &inputs[0];
625 			void*		out	= &outputs[0];
626 
627 			m_executor->execute((int)inputs.size(), &in, &out);
628 		}
629 
630 		// Verify
631 		{
632 			const int	numValues	= (int)inputs.size();
633 			const int	maxPrints	= 10;
634 			int			numFailed	= 0;
635 
636 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
637 			{
638 				const deUint16	ref0	= (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
639 				const deUint16	ref1	= (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
640 				const deUint32	ref		= (ref1 << 16) | ref0;
641 				const deUint32	res		= outputs[valNdx];
642 				const deUint16	res0	= (deUint16)(res & 0xffff);
643 				const deUint16	res1	= (deUint16)(res >> 16);
644 				const int		diff0	= de::abs((int)ref0 - (int)res0);
645 				const int		diff1	= de::abs((int)ref1 - (int)res1);
646 
647 				if (diff0 > maxDiff || diff1 > maxDiff)
648 				{
649 					if (numFailed < maxPrints)
650 					{
651 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
652 															   << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
653 															   << ", got " << tcu::toHex(res)
654 															   << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
655 										   << TestLog::EndMessage;
656 					}
657 					else if (numFailed == maxPrints)
658 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
659 
660 					numFailed += 1;
661 				}
662 			}
663 
664 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
665 
666 			if (numFailed == 0)
667 				return tcu::TestStatus::pass("Pass");
668 			else
669 				return tcu::TestStatus::fail("Result comparison failed");
670 
671 		}
672 	}
673 };
674 
675 class PackHalf2x16Case : public ShaderPackingFunctionCase
676 {
677 public:
PackHalf2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)678 	PackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
679 		: ShaderPackingFunctionCase	(testCtx, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
680 	{
681 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
682 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
683 
684 		m_spec.source = "out0 = packHalf2x16(in0);";
685 	}
686 
createInstance(Context & ctx) const687 	TestInstance* createInstance (Context& ctx) const
688 	{
689 		return new PackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
690 	}
691 
692 };
693 
694 class UnpackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
695 {
696 	enum Sign
697 	{
698 		POSITIVE								= 0,
699 		NEGATIVE
700 	};
701 	enum SubnormalizedConversionType
702 	{
703 		UNKNOWN									= 0,
704 		CONVERTED,
705 		ZERO_FLUSHED,
706 	};
707 public:
UnpackHalf2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)708 	UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
709 	: ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
710 	{
711 	}
712 
iterate(void)713 	tcu::TestStatus iterate (void)
714 	{
715 		const int					minExp		= -14;
716 		const int					maxExp		= 15;
717 		const int					mantBits	= 10;
718 		const deUint32				mantBitMask = (1u << mantBits) - 1u;
719 		tcu::TestLog&				log			= m_testCtx.getLog();
720 
721 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
722 		std::vector<deUint32>		inputs;
723 		std::vector<tcu::Vec2>		outputs;
724 
725 		// Special values.
726 		inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
727 		inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
728 		inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
729 		inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
730 		// Special subnormal value: single lowest bit set
731 		inputs.push_back((tcu::Float16(composeHalfFloat(POSITIVE, 0u, 1u)).bits() << 16)
732 						| tcu::Float16(composeHalfFloat(NEGATIVE, 0u, 1u)).bits());
733 		// Special subnormal value: single highest fraction bit set
734 		inputs.push_back((tcu::Float16(composeHalfFloat(NEGATIVE, 0u, 1u << (mantBits - 1u))).bits() << 16)
735 						| tcu::Float16(composeHalfFloat(POSITIVE, 0u, 1u << (mantBits - 1u))).bits());
736 		// Special subnormal value: all fraction bits set
737 		inputs.push_back((tcu::Float16(composeHalfFloat(POSITIVE, 0u, mantBitMask)).bits() << 16)
738 						| tcu::Float16(composeHalfFloat(NEGATIVE, 0u, mantBitMask)).bits());
739 
740 		// Construct random values.
741 		for (int ndx = 0; ndx < 90; ndx++)
742 		{
743 			deUint32 inVal = 0;
744 			for (int c = 0; c < 2; c++)
745 			{
746 				const int		s			= rnd.getBool() ? 1 : -1;
747 				const int		exp			= rnd.getInt(minExp, maxExp);
748 				const deUint32	mantissa	= rnd.getUint32() & mantBitMask;
749 				const deUint16	value		= tcu::Float16::construct(s, exp != 0 ? exp : 1 /* avoid denorm */, static_cast<deUint16>((1u<<10) | mantissa)).bits();
750 
751 				inVal |= value << (16u * c);
752 			}
753 			inputs.push_back(inVal);
754 		}
755 		for (int ndx = 0; ndx < 15; ndx++)
756 		{
757 			deUint32 inVal = 0;
758 			for (int c = 0; c < 2; c++)
759 			{
760 				const Sign		sign		= rnd.getBool()? POSITIVE : NEGATIVE;
761 				const deUint32	mantissa	= rnd.getUint32() & mantBitMask;
762 				const deUint16	value		= tcu::Float16(composeHalfFloat(sign, 0u /* force denorm */, mantissa)).bits();
763 
764 				inVal |= value << (16u * c);
765 			}
766 			inputs.push_back(inVal);
767 		}
768 
769 		outputs.resize(inputs.size());
770 
771 		log << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
772 
773 		{
774 			const void*	in	= &inputs[0];
775 			void*		out	= &outputs[0];
776 
777 			m_executor->execute((int)inputs.size(), &in, &out);
778 		}
779 
780 		// Verify
781 		{
782 			const int					numValues	= (int)inputs.size();
783 			const int					maxPrints	= 10;
784 			int							numFailed	= 0;
785 			SubnormalizedConversionType conversion	= UNKNOWN;
786 
787 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
788 			{
789 				const deUint16			in0			= (deUint16)(inputs[valNdx] & 0xffff);
790 				const deUint16			in1			= (deUint16)(inputs[valNdx] >> 16);
791 				const float				res0		= outputs[valNdx].x();
792 				const float				res1		= outputs[valNdx].y();
793 
794 				const deBool			value0		= checkValue(in0, res0, conversion);
795 				// note: do not avoid calling checkValue for in1 if it failed for in0 by using && laziness
796 				// checkValue may potentially change 'conversion' parameter if it was set to UNKNOWN so far
797 				const deBool			value1		= checkValue(in1, res1, conversion);
798 				const deBool			valuesOK	= value0 && value1;
799 
800 				if (!valuesOK)
801 				{
802 					if (numFailed < maxPrints)
803 						printErrorMessage(log, valNdx, in0, in1, res0, res1);
804 					else if (numFailed == maxPrints)
805 						log << TestLog::Message << "..." << TestLog::EndMessage;
806 					++numFailed;
807 				}
808 			}
809 
810 			log << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
811 
812 			if (numFailed == 0)
813 				return tcu::TestStatus::pass("Pass");
814 			else
815 				return tcu::TestStatus::fail("Result comparison failed");
816 		}
817 	}
818 private:
checkValue(deUint16 inValue,float outValue,SubnormalizedConversionType & conversion)819 	deBool checkValue (deUint16 inValue, float outValue, SubnormalizedConversionType& conversion)
820 	{
821 		const tcu::Float16		temp			= tcu::Float16(inValue);
822 		const float				ref				= temp.asFloat();
823 		const deUint32			refBits			= tcu::Float32(ref).bits();
824 		const deUint32			resBits			= tcu::Float32(outValue).bits();
825 		const deBool			bitMatch		= (refBits ^ resBits) == 0u;
826 		const deBool			denorm			= temp.isDenorm();
827 
828 		if (conversion != CONVERTED && denorm)
829 		{
830 			if (resBits == 0 || (ref < 0 && resBits == 0x80000000UL))
831 			{
832 				conversion = ZERO_FLUSHED;
833 				return DE_TRUE;
834 			}
835 			if (conversion != ZERO_FLUSHED && bitMatch)
836 			{
837 				conversion = CONVERTED;
838 				return DE_TRUE;
839 			}
840 			return DE_FALSE;
841 		}
842 		else if (bitMatch)
843 			return DE_TRUE;
844 		return DE_FALSE;
845 	}
printErrorMessage(tcu::TestLog & log,deUint32 valNdx,deUint16 in0,deUint16 in1,float out0,float out1)846 	void printErrorMessage (tcu::TestLog& log, deUint32 valNdx, deUint16 in0, deUint16 in1, float out0, float out1)
847 	{
848 		const float			ref0		= tcu::Float16(in0).asFloat();
849 		const deUint32		refBits0	= tcu::Float32(ref0).bits();
850 		const deUint32		resBits0	= tcu::Float32(out0).bits();
851 		const float			ref1		= tcu::Float16(in1).asFloat();
852 		const deUint32		refBits1	= tcu::Float32(ref1).bits();
853 		const deUint32		resBits1	= tcu::Float32(out1).bits();
854 		log << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
855 			<< "  expected unpackHalf2x16(" << tcu::toHex((in1 << 16u) | in0) << ") = "
856 			<< "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
857 			<< ", got vec2(" << out0 << " / " << tcu::toHex(resBits0) << ", " << out1 << " / " << tcu::toHex(resBits1) << ")"
858 			<< TestLog::EndMessage;
859 	}
composeHalfFloat(Sign sign,deUint32 exponent,deUint32 significand)860 	deUint16 composeHalfFloat (Sign sign, deUint32 exponent, deUint32 significand)
861 	{
862 		const deUint32		BitMask_05	= (1u << 5u)  - 1u;
863 		const deUint32		BitMask_10	= (1u << 10u) - 1u;
864 		const deUint32		BitMask_16	= (1u << 16u) - 1u;
865 		DE_UNREF(BitMask_05);
866 		DE_UNREF(BitMask_10);
867 		DE_UNREF(BitMask_16);
868 		DE_ASSERT((exponent & ~BitMask_05) == 0u);
869 		DE_ASSERT((significand & ~BitMask_10) == 0u);
870 		const deUint32		value		= (((sign == NEGATIVE ? 1u : 0u) << 5u | exponent) << 10u) | significand;
871 		DE_ASSERT((value & ~BitMask_16) == 0u);
872 		return static_cast<deUint16>(value);
873 	}
874 };
875 
876 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
877 {
878 public:
UnpackHalf2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)879 	UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
880 		: ShaderPackingFunctionCase	(testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
881 	{
882 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
883 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
884 
885 		m_spec.source = "out0 = unpackHalf2x16(in0);";
886 	}
887 
createInstance(Context & ctx) const888 	TestInstance* createInstance (Context& ctx) const
889 	{
890 		return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
891 	}
892 
893 };
894 
895 class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
896 {
897 public:
PackSnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)898 	PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
899 		: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
900 		, m_precision						(precision)
901 	{
902 	}
903 
iterate(void)904 	tcu::TestStatus iterate (void)
905 	{
906 		de::Random					rnd			(deStringHash(m_name) ^ 0x42f2c0);
907 		std::vector<tcu::Vec4>		inputs;
908 		std::vector<deUint32>		outputs;
909 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1	:		// Rounding only.
910 												  m_precision == glu::PRECISION_MEDIUMP	? 1	:		// (2^-10) * (2^7) + 1
911 												  m_precision == glu::PRECISION_LOWP	? 2	: 0;	// (2^-8) * (2^7) + 1
912 
913 		// Special values to check.
914 		inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
915 		inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
916 		inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
917 		inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
918 		inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
919 
920 		// Random values, mostly in range.
921 		for (int ndx = 0; ndx < 15; ndx++)
922 		{
923 			inputs.push_back(tcu::randomVector<float, 4>(rnd, tcu::Vec4(-1.25f), tcu::Vec4(1.25f)));
924 		}
925 
926 		// Large random values.
927 		for (int ndx = 0; ndx < 80; ndx++)
928 		{
929 			inputs.push_back(tcu::randomVector<float, 4>(rnd, tcu::Vec4(-0.5e6f), tcu::Vec4(0.5e6f)));
930 		}
931 
932 		outputs.resize(inputs.size());
933 
934 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
935 
936 		{
937 			const void*	in	= &inputs[0];
938 			void*		out	= &outputs[0];
939 
940 			m_executor->execute((int)inputs.size(), &in, &out);
941 		}
942 
943 		// Verify
944 		{
945 			const int	numValues	= (int)inputs.size();
946 			const int	maxPrints	= 10;
947 			int			numFailed	= 0;
948 
949 			for (int valNdx = 0; valNdx < numValues; valNdx++)
950 			{
951 				const deUint16	ref0	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
952 				const deUint16	ref1	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
953 				const deUint16	ref2	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
954 				const deUint16	ref3	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
955 				const deUint32	ref		= (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
956 				const deUint32	res		= outputs[valNdx];
957 				const deUint16	res0	= (deUint8)(res & 0xff);
958 				const deUint16	res1	= (deUint8)((res >> 8) & 0xff);
959 				const deUint16	res2	= (deUint8)((res >> 16) & 0xff);
960 				const deUint16	res3	= (deUint8)((res >> 24) & 0xff);
961 				const int		diff0	= de::abs((int)ref0 - (int)res0);
962 				const int		diff1	= de::abs((int)ref1 - (int)res1);
963 				const int		diff2	= de::abs((int)ref2 - (int)res2);
964 				const int		diff3	= de::abs((int)ref3 - (int)res3);
965 
966 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
967 				{
968 					if (numFailed < maxPrints)
969 					{
970 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
971 															   << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
972 															   << ", got " << tcu::toHex(res)
973 															   << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
974 										   << TestLog::EndMessage;
975 					}
976 					else if (numFailed == maxPrints)
977 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
978 
979 					numFailed += 1;
980 				}
981 			}
982 
983 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
984 
985 			if (numFailed == 0)
986 				return tcu::TestStatus::pass("Pass");
987 			else
988 				return tcu::TestStatus::fail("Result comparison failed");
989 
990 		}
991 	}
992 
993 private:
994 	const glu::Precision m_precision;
995 };
996 
997 class PackSnorm4x8Case : public ShaderPackingFunctionCase
998 {
999 public:
PackSnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)1000 	PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1001 		: ShaderPackingFunctionCase	(testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
1002 		, m_precision				(precision)
1003 	{
1004 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1005 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1006 
1007 		m_spec.source = "out0 = packSnorm4x8(in0);";
1008 	}
1009 
createInstance(Context & ctx) const1010 	TestInstance* createInstance (Context& ctx) const
1011 	{
1012 		return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1013 	}
1014 
1015 private:
1016 	const glu::Precision m_precision;
1017 };
1018 
1019 class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1020 {
1021 public:
UnpackSnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)1022 	UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1023 		: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
1024 	{
1025 	}
1026 
iterate(void)1027 	tcu::TestStatus iterate (void)
1028 	{
1029 		const deUint32				maxDiff		= 1; // Rounding error.
1030 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
1031 		std::vector<deUint32>		inputs;
1032 		std::vector<tcu::Vec4>		outputs;
1033 
1034 		inputs.push_back(0x00000000u);
1035 		inputs.push_back(0x7fff8000u);
1036 		inputs.push_back(0x80007fffu);
1037 		inputs.push_back(0xffffffffu);
1038 		inputs.push_back(0x0001fffeu);
1039 
1040 		// Random values.
1041 		for (int ndx = 0; ndx < 95; ndx++)
1042 			inputs.push_back(rnd.getUint32());
1043 
1044 		outputs.resize(inputs.size());
1045 
1046 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1047 
1048 		{
1049 			const void*	in	= &inputs[0];
1050 			void*		out	= &outputs[0];
1051 
1052 			m_executor->execute((int)inputs.size(), &in, &out);
1053 		}
1054 
1055 		// Verify
1056 		{
1057 			const int	numValues	= (int)inputs.size();
1058 			const int	maxPrints	= 10;
1059 			int			numFailed	= 0;
1060 
1061 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1062 			{
1063 				const deInt8	in0		= (deInt8)(deUint8)(inputs[valNdx] & 0xff);
1064 				const deInt8	in1		= (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
1065 				const deInt8	in2		= (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
1066 				const deInt8	in3		= (deInt8)(deUint8)(inputs[valNdx] >> 24);
1067 				const float		ref0	= de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
1068 				const float		ref1	= de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
1069 				const float		ref2	= de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
1070 				const float		ref3	= de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
1071 				const float		res0	= outputs[valNdx].x();
1072 				const float		res1	= outputs[valNdx].y();
1073 				const float		res2	= outputs[valNdx].z();
1074 				const float		res3	= outputs[valNdx].w();
1075 
1076 				const deUint32	diff0	= getUlpDiff(ref0, res0);
1077 				const deUint32	diff1	= getUlpDiff(ref1, res1);
1078 				const deUint32	diff2	= getUlpDiff(ref2, res2);
1079 				const deUint32	diff3	= getUlpDiff(ref3, res3);
1080 
1081 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1082 				{
1083 					if (numFailed < maxPrints)
1084 					{
1085 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1086 															   << "  expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1087 															   << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1088 															   << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1089 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1090 										   << TestLog::EndMessage;
1091 					}
1092 					else if (numFailed == maxPrints)
1093 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1094 
1095 					numFailed += 1;
1096 				}
1097 			}
1098 
1099 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1100 
1101 			if (numFailed == 0)
1102 				return tcu::TestStatus::pass("Pass");
1103 			else
1104 				return tcu::TestStatus::fail("Result comparison failed");
1105 
1106 		}
1107 	}
1108 };
1109 
1110 
1111 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
1112 {
1113 public:
UnpackSnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)1114 	UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1115 		: ShaderPackingFunctionCase	(testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
1116 	{
1117 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1118 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1119 
1120 		m_spec.source = "out0 = unpackSnorm4x8(in0);";
1121 	}
1122 
createInstance(Context & ctx) const1123 	TestInstance* createInstance (Context& ctx) const
1124 	{
1125 		return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1126 	}
1127 
1128 };
1129 
1130 class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1131 {
1132 public:
PackUnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)1133 	PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
1134 		: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
1135 		, m_precision						(precision)
1136 	{
1137 	}
1138 
iterate(void)1139 	tcu::TestStatus iterate (void)
1140 	{
1141 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
1142 		std::vector<tcu::Vec4>		inputs;
1143 		std::vector<deUint32>		outputs;
1144 		const int					maxDiff		= m_precision == glu::PRECISION_HIGHP	? 1	:		// Rounding only.
1145 												  m_precision == glu::PRECISION_MEDIUMP	? 1	:		// (2^-10) * (2^8) + 1
1146 												  m_precision == glu::PRECISION_LOWP	? 2	: 0;	// (2^-8) * (2^8) + 1
1147 
1148 		// Special values to check.
1149 		inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1150 		inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1151 		inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1152 		inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1153 		inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1154 
1155 		// Random values, mostly in range.
1156 		for (int ndx = 0; ndx < 15; ndx++)
1157 		{
1158 			inputs.push_back(tcu::randomVector<float, 4>(rnd, tcu::Vec4(-0.125f), tcu::Vec4(1.125f)));
1159 		}
1160 
1161 		// Large random values.
1162 		for (int ndx = 0; ndx < 80; ndx++)
1163 		{
1164 			inputs.push_back(tcu::randomVector<float, 4>(rnd, tcu::Vec4(-1e5f), tcu::Vec4(0.9e6f)));
1165 		}
1166 
1167 		outputs.resize(inputs.size());
1168 
1169 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1170 
1171 		{
1172 			const void*	in	= &inputs[0];
1173 			void*		out	= &outputs[0];
1174 
1175 			m_executor->execute((int)inputs.size(), &in, &out);
1176 		}
1177 
1178 		// Verify
1179 		{
1180 			const int	numValues	= (int)inputs.size();
1181 			const int	maxPrints	= 10;
1182 			int			numFailed	= 0;
1183 
1184 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1185 			{
1186 				const deUint16	ref0	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1187 				const deUint16	ref1	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1188 				const deUint16	ref2	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1189 				const deUint16	ref3	= (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1190 				const deUint32	ref		= (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1191 				const deUint32	res		= outputs[valNdx];
1192 				const deUint16	res0	= (deUint8)(res & 0xff);
1193 				const deUint16	res1	= (deUint8)((res >> 8) & 0xff);
1194 				const deUint16	res2	= (deUint8)((res >> 16) & 0xff);
1195 				const deUint16	res3	= (deUint8)((res >> 24) & 0xff);
1196 				const int		diff0	= de::abs((int)ref0 - (int)res0);
1197 				const int		diff1	= de::abs((int)ref1 - (int)res1);
1198 				const int		diff2	= de::abs((int)ref2 - (int)res2);
1199 				const int		diff3	= de::abs((int)ref3 - (int)res3);
1200 
1201 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1202 				{
1203 					if (numFailed < maxPrints)
1204 					{
1205 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1206 															   << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1207 															   << ", got " << tcu::toHex(res)
1208 															   << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1209 										   << TestLog::EndMessage;
1210 					}
1211 					else if (numFailed == maxPrints)
1212 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1213 
1214 					numFailed += 1;
1215 				}
1216 			}
1217 
1218 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1219 
1220 			if (numFailed == 0)
1221 				return tcu::TestStatus::pass("Pass");
1222 			else
1223 				return tcu::TestStatus::fail("Result comparison failed");
1224 
1225 		}
1226 	}
1227 
1228 private:
1229 	const glu::Precision m_precision;
1230 };
1231 
1232 class PackUnorm4x8Case : public ShaderPackingFunctionCase
1233 {
1234 public:
PackUnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)1235 	PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1236 		: ShaderPackingFunctionCase	(testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
1237 		, m_precision				(precision)
1238 	{
1239 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1240 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1241 
1242 		m_spec.source = "out0 = packUnorm4x8(in0);";
1243 	}
1244 
createInstance(Context & ctx) const1245 	TestInstance* createInstance (Context& ctx) const
1246 	{
1247 		return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1248 	}
1249 
1250 private:
1251 	const glu::Precision m_precision;
1252 };
1253 
1254 class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1255 {
1256 public:
UnpackUnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)1257 	UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1258 		: ShaderPackingFunctionTestInstance	(context, shaderType, spec, name)
1259 	{
1260 	}
1261 
iterate(void)1262 	tcu::TestStatus iterate (void)
1263 	{
1264 		const deUint32				maxDiff		= 1; // Rounding error.
1265 		de::Random					rnd			(deStringHash(m_name) ^ 0x776002);
1266 		std::vector<deUint32>		inputs;
1267 		std::vector<tcu::Vec4>		outputs;
1268 
1269 		inputs.push_back(0x00000000u);
1270 		inputs.push_back(0x7fff8000u);
1271 		inputs.push_back(0x80007fffu);
1272 		inputs.push_back(0xffffffffu);
1273 		inputs.push_back(0x0001fffeu);
1274 
1275 		// Random values.
1276 		for (int ndx = 0; ndx < 95; ndx++)
1277 			inputs.push_back(rnd.getUint32());
1278 
1279 		outputs.resize(inputs.size());
1280 
1281 		m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1282 
1283 		{
1284 			const void*	in	= &inputs[0];
1285 			void*		out	= &outputs[0];
1286 
1287 			m_executor->execute((int)inputs.size(), &in, &out);
1288 		}
1289 
1290 		// Verify
1291 		{
1292 			const int	numValues	= (int)inputs.size();
1293 			const int	maxPrints	= 10;
1294 			int			numFailed	= 0;
1295 
1296 			for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1297 			{
1298 				const deUint8	in0		= (deUint8)(inputs[valNdx] & 0xff);
1299 				const deUint8	in1		= (deUint8)((inputs[valNdx] >> 8) & 0xff);
1300 				const deUint8	in2		= (deUint8)((inputs[valNdx] >> 16) & 0xff);
1301 				const deUint8	in3		= (deUint8)(inputs[valNdx] >> 24);
1302 				const float		ref0	= de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1303 				const float		ref1	= de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1304 				const float		ref2	= de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1305 				const float		ref3	= de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1306 				const float		res0	= outputs[valNdx].x();
1307 				const float		res1	= outputs[valNdx].y();
1308 				const float		res2	= outputs[valNdx].z();
1309 				const float		res3	= outputs[valNdx].w();
1310 
1311 				const deUint32	diff0	= getUlpDiff(ref0, res0);
1312 				const deUint32	diff1	= getUlpDiff(ref1, res1);
1313 				const deUint32	diff2	= getUlpDiff(ref2, res2);
1314 				const deUint32	diff3	= getUlpDiff(ref3, res3);
1315 
1316 				if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1317 				{
1318 					if (numFailed < maxPrints)
1319 					{
1320 						m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1321 															   << "  expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1322 															   << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1323 															   << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1324 															   << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1325 										   << TestLog::EndMessage;
1326 					}
1327 					else if (numFailed == maxPrints)
1328 						m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1329 
1330 					numFailed += 1;
1331 				}
1332 			}
1333 
1334 			m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1335 
1336 			if (numFailed == 0)
1337 				return tcu::TestStatus::pass("Pass");
1338 			else
1339 				return tcu::TestStatus::fail("Result comparison failed");
1340 
1341 		}
1342 	}
1343 };
1344 
1345 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1346 {
1347 public:
UnpackUnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)1348 	UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1349 		: ShaderPackingFunctionCase	(testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1350 	{
1351 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1352 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1353 
1354 		m_spec.source = "out0 = unpackUnorm4x8(in0);";
1355 	}
1356 
createInstance(Context & ctx) const1357 	TestInstance* createInstance (Context& ctx) const
1358 	{
1359 		return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1360 	}
1361 
1362 };
1363 
ShaderPackingFunctionTests(tcu::TestContext & testCtx)1364 ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
1365 	: tcu::TestCaseGroup	(testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
1366 {
1367 }
1368 
~ShaderPackingFunctionTests(void)1369 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1370 {
1371 }
1372 
init(void)1373 void ShaderPackingFunctionTests::init (void)
1374 {
1375 	// New built-in functions in GLES 3.1
1376 	{
1377 		const glu::ShaderType allShaderTypes[] =
1378 		{
1379 			glu::SHADERTYPE_VERTEX,
1380 			glu::SHADERTYPE_TESSELLATION_CONTROL,
1381 			glu::SHADERTYPE_TESSELLATION_EVALUATION,
1382 			glu::SHADERTYPE_GEOMETRY,
1383 			glu::SHADERTYPE_FRAGMENT,
1384 			glu::SHADERTYPE_COMPUTE
1385 		};
1386 
1387 		// packSnorm4x8
1388 		for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1389 		{
1390 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1391 				addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1392 		}
1393 
1394 		// unpackSnorm4x8
1395 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1396 			addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1397 
1398 		// packUnorm4x8
1399 		for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1400 		{
1401 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1402 				addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1403 		}
1404 
1405 		// unpackUnorm4x8
1406 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1407 			addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1408 	}
1409 
1410 	// GLES 3 functions in new shader types.
1411 	{
1412 		const glu::ShaderType newShaderTypes[] =
1413 		{
1414 			glu::SHADERTYPE_GEOMETRY,
1415 			glu::SHADERTYPE_COMPUTE
1416 		};
1417 
1418 		// packSnorm2x16
1419 		for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1420 		{
1421 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1422 				addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1423 		}
1424 
1425 		// unpackSnorm2x16
1426 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1427 			addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1428 
1429 		// packUnorm2x16
1430 		for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1431 		{
1432 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1433 				addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1434 		}
1435 
1436 		// unpackUnorm2x16
1437 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1438 			addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1439 
1440 		// packHalf2x16
1441 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1442 			addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1443 
1444 		// unpackHalf2x16
1445 		for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1446 			addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1447 	}
1448 }
1449 
1450 } // shaderexecutor
1451 } // vkt
1452