1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Google Inc.
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 SPIR-V Assembly Tests for the VK_KHR_16bit_storage
22 *//*--------------------------------------------------------------------*/
23
24// VK_KHR_16bit_storage
25//
26// \todo [2017-02-08 antiagainst] Additional corner cases to check:
27//
28// * Test OpAccessChain with subword types
29//  * For newly enabled types T:
30//    * For composite types: vector, matrix, structures, array over T:
31//      1. Use OpAccessChain to form a pointer to a subword type.
32//      2. Load the subword value X16.
33//      3. Convert X16 to X32.
34//      4. Store X32 to BufferBlock.
35//      5. Host inspects X32.
36// * Test {StorageInputOutput16} 16-to-16:
37//   * For newly enabled types T:
38//     1. Host creates X16 stream values of type T.
39//     2. Shaders have corresponding capability.
40//     3. For each viable shader stage:
41//       3a. Load X16 Input variable.
42//       3b. Store X16 to Output variable.
43//     4. Host inspects resulting values.
44// * Test {StorageInputOutput16} 16-to-16 one value to two:
45//     Like the previous test, but write X16 to two different output variables.
46//     (Checks that the 16-bit intermediate value can be used twice.)
47
48#include "vktSpvAsm16bitStorageTests.hpp"
49
50#include "tcuFloat.hpp"
51#include "tcuRGBA.hpp"
52#include "tcuStringTemplate.hpp"
53#include "tcuTestLog.hpp"
54#include "tcuVectorUtil.hpp"
55
56#include "vkDefs.hpp"
57#include "vkDeviceUtil.hpp"
58#include "vkMemUtil.hpp"
59#include "vkPlatform.hpp"
60#include "vkPrograms.hpp"
61#include "vkQueryUtil.hpp"
62#include "vkRef.hpp"
63#include "vkRefUtil.hpp"
64#include "vkStrUtil.hpp"
65#include "vkTypeUtil.hpp"
66
67#include "deRandom.hpp"
68#include "deStringUtil.hpp"
69#include "deUniquePtr.hpp"
70#include "deMath.h"
71
72#include "vktSpvAsmComputeShaderCase.hpp"
73#include "vktSpvAsmComputeShaderTestUtil.hpp"
74#include "vktSpvAsmGraphicsShaderTestUtil.hpp"
75#include "vktTestCaseUtil.hpp"
76#include "vktTestGroupUtil.hpp"
77
78#include <limits>
79#include <map>
80#include <string>
81#include <sstream>
82#include <utility>
83
84namespace vkt
85{
86namespace SpirVAssembly
87{
88
89using namespace vk;
90using std::map;
91using std::string;
92using std::vector;
93using tcu::IVec3;
94using tcu::IVec4;
95using tcu::RGBA;
96using tcu::TestLog;
97using tcu::TestStatus;
98using tcu::Vec4;
99using de::UniquePtr;
100using tcu::StringTemplate;
101using tcu::Vec4;
102
103namespace
104{
105
106struct Capability
107{
108	const char*				name;
109	const char*				cap;
110	const char*				decor;
111	vk::VkDescriptorType	dtype;
112};
113
114static const Capability	CAPABILITIES[]	=
115{
116	{"uniform_buffer_block",	"StorageUniformBufferBlock16",	"BufferBlock",	VK_DESCRIPTOR_TYPE_STORAGE_BUFFER},
117	{"uniform",					"StorageUniform16",				"Block",		VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER},
118};
119
120VulkanFeatures	get16BitStorageFeatures	(const char* cap)
121{
122	VulkanFeatures features;
123	if (string(cap) == "uniform_buffer_block")
124		features.ext16BitStorage = EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK;
125	else if (string(cap) == "uniform")
126		features.ext16BitStorage = EXT16BITSTORAGEFEATURES_UNIFORM;
127	else
128		DE_ASSERT(false && "not supported");
129
130	return features;
131}
132
133
134// Batch function to check arrays of 16-bit floats.
135//
136// For comparing 16-bit floats, we need to consider both RTZ and RTE. So we can only recalculate
137// the expected values here instead of get the expected values directly from the test case.
138// Thus we need original floats here but not expected outputs.
139template<RoundingModeFlags RoundingMode>
140bool graphicsCheck16BitFloats (const std::vector<Resource>&	originalFloats,
141							   const vector<AllocationSp>&	outputAllocs,
142							   const std::vector<Resource>&	/* expectedOutputs */,
143							   tcu::TestLog&				log)
144{
145	if (outputAllocs.size() != originalFloats.size())
146		return false;
147
148	for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
149	{
150		vector<deUint8>	originalBytes;
151		originalFloats[outputNdx].second->getBytes(originalBytes);
152
153		const deUint16*	returned	= static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
154		const float*	original	= reinterpret_cast<const float*>(&originalBytes.front());
155		const deUint32	count		= static_cast<deUint32>(originalBytes.size() / sizeof(float));
156
157		for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
158			if (!compare16BitFloat(original[numNdx], returned[numNdx], RoundingMode, log))
159				return false;
160	}
161
162	return true;
163}
164
165template<RoundingModeFlags RoundingMode>
166bool computeCheck16BitFloats (const std::vector<BufferSp>&	originalFloats,
167							  const vector<AllocationSp>&	outputAllocs,
168							  const std::vector<BufferSp>&	/* expectedOutputs */,
169							  tcu::TestLog&					log)
170{
171	if (outputAllocs.size() != originalFloats.size())
172		return false;
173
174	for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
175	{
176		vector<deUint8>	originalBytes;
177		originalFloats[outputNdx]->getBytes(originalBytes);
178
179		const deUint16*	returned	= static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
180		const float*	original	= reinterpret_cast<const float*>(&originalBytes.front());
181		const deUint32	count		= static_cast<deUint32>(originalBytes.size() / sizeof(float));
182
183		for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
184			if (!compare16BitFloat(original[numNdx], returned[numNdx], RoundingMode, log))
185				return false;
186	}
187
188	return true;
189}
190
191
192// Batch function to check arrays of 32-bit floats.
193//
194// For comparing 32-bit floats, we just need the expected value precomputed in the test case.
195// So we need expected outputs here but not original floats.
196bool check32BitFloats (const std::vector<Resource>&		/* originalFloats */,
197					   const std::vector<AllocationSp>& outputAllocs,
198					   const std::vector<Resource>&		expectedOutputs,
199					   tcu::TestLog&					log)
200{
201	if (outputAllocs.size() != expectedOutputs.size())
202		return false;
203
204	for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
205	{
206		vector<deUint8>	expectedBytes;
207		expectedOutputs[outputNdx].second->getBytes(expectedBytes);
208
209		const float*	returnedAsFloat	= static_cast<const float*>(outputAllocs[outputNdx]->getHostPtr());
210		const float*	expectedAsFloat	= reinterpret_cast<const float*>(&expectedBytes.front());
211		const deUint32	count			= static_cast<deUint32>(expectedBytes.size() / sizeof(float));
212
213		for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
214			if (!compare32BitFloat(expectedAsFloat[numNdx], returnedAsFloat[numNdx], log))
215				return false;
216	}
217
218	return true;
219}
220
221// Overload for compute pipeline
222bool check32BitFloats (const std::vector<BufferSp>&		/* originalFloats */,
223					   const std::vector<AllocationSp>& outputAllocs,
224					   const std::vector<BufferSp>&		expectedOutputs,
225					   tcu::TestLog&					log)
226{
227	if (outputAllocs.size() != expectedOutputs.size())
228		return false;
229
230	for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
231	{
232		vector<deUint8>	expectedBytes;
233		expectedOutputs[outputNdx]->getBytes(expectedBytes);
234
235		const float*	returnedAsFloat	= static_cast<const float*>(outputAllocs[outputNdx]->getHostPtr());
236		const float*	expectedAsFloat	= reinterpret_cast<const float*>(&expectedBytes.front());
237		const deUint32	count			= static_cast<deUint32>(expectedBytes.size() / sizeof(float));
238
239		for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
240			if (!compare32BitFloat(expectedAsFloat[numNdx], returnedAsFloat[numNdx], log))
241				return false;
242	}
243
244	return true;
245}
246
247// Generate and return 32-bit integers.
248//
249// Expected count to be at least 16.
250vector<deInt32> getInt32s (de::Random& rnd, const deUint32 count)
251{
252	vector<deInt32>		data;
253
254	data.reserve(count);
255
256	// Make sure we have boundary numbers.
257	data.push_back(deInt32(0x00000000));  // 0
258	data.push_back(deInt32(0x00000001));  // 1
259	data.push_back(deInt32(0x0000002a));  // 42
260	data.push_back(deInt32(0x00007fff));  // 32767
261	data.push_back(deInt32(0x00008000));  // 32768
262	data.push_back(deInt32(0x0000ffff));  // 65535
263	data.push_back(deInt32(0x00010000));  // 65536
264	data.push_back(deInt32(0x7fffffff));  // 2147483647
265	data.push_back(deInt32(0x80000000));  // -2147483648
266	data.push_back(deInt32(0x80000001));  // -2147483647
267	data.push_back(deInt32(0xffff0000));  // -65536
268	data.push_back(deInt32(0xffff0001));  // -65535
269	data.push_back(deInt32(0xffff8000));  // -32768
270	data.push_back(deInt32(0xffff8001));  // -32767
271	data.push_back(deInt32(0xffffffd6));  // -42
272	data.push_back(deInt32(0xffffffff));  // -1
273
274	DE_ASSERT(count >= data.size());
275
276	for (deUint32 numNdx = static_cast<deUint32>(data.size()); numNdx < count; ++numNdx)
277		data.push_back(static_cast<deInt32>(rnd.getUint32()));
278
279	return data;
280}
281
282// Generate and return 16-bit integers.
283//
284// Expected count to be at least 8.
285vector<deInt16> getInt16s (de::Random& rnd, const deUint32 count)
286{
287	vector<deInt16>		data;
288
289	data.reserve(count);
290
291	// Make sure we have boundary numbers.
292	data.push_back(deInt16(0x0000));  // 0
293	data.push_back(deInt16(0x0001));  // 1
294	data.push_back(deInt16(0x002a));  // 42
295	data.push_back(deInt16(0x7fff));  // 32767
296	data.push_back(deInt16(0x8000));  // -32868
297	data.push_back(deInt16(0x8001));  // -32767
298	data.push_back(deInt16(0xffd6));  // -42
299	data.push_back(deInt16(0xffff));  // -1
300
301	DE_ASSERT(count >= data.size());
302
303	for (deUint32 numNdx = static_cast<deUint32>(data.size()); numNdx < count; ++numNdx)
304		data.push_back(static_cast<deInt16>(rnd.getUint16()));
305
306	return data;
307}
308
309// IEEE-754 floating point numbers:
310// +--------+------+----------+-------------+
311// | binary | sign | exponent | significand |
312// +--------+------+----------+-------------+
313// | 16-bit |  1   |    5     |     10      |
314// +--------+------+----------+-------------+
315// | 32-bit |  1   |    8     |     23      |
316// +--------+------+----------+-------------+
317//
318// 16-bit floats:
319//
320// 0   000 00   00 0000 0001 (0x0001: 2e-24:         minimum positive denormalized)
321// 0   000 00   11 1111 1111 (0x03ff: 2e-14 - 2e-24: maximum positive denormalized)
322// 0   000 01   00 0000 0000 (0x0400: 2e-14:         minimum positive normalized)
323//
324// 32-bit floats:
325//
326// 0   011 1110 1   001 0000 0000 0000 0000 0000 (0x3e900000: 0.28125: with exact match in 16-bit normalized)
327// 0   011 1000 1   000 0000 0011 0000 0000 0000 (0x38803000: exact half way within two 16-bit normalized; round to zero: 0x0401)
328// 1   011 1000 1   000 0000 0011 0000 0000 0000 (0xb8803000: exact half way within two 16-bit normalized; round to zero: 0x8402)
329// 0   011 1000 1   000 0000 1111 1111 0000 0000 (0x3880ff00: not exact half way within two 16-bit normalized; round to zero: 0x0403)
330// 1   011 1000 1   000 0000 1111 1111 0000 0000 (0xb880ff00: not exact half way within two 16-bit normalized; round to zero: 0x8404)
331
332
333// Generate and return 32-bit floats
334//
335// The first 24 number pairs are manually picked, while the rest are randomly generated.
336// Expected count to be at least 24 (numPicks).
337vector<float> getFloat32s (de::Random& rnd, deUint32 count)
338{
339	vector<float>		float32;
340
341	float32.reserve(count);
342
343	// Zero
344	float32.push_back(0.f);
345	float32.push_back(-0.f);
346	// Infinity
347	float32.push_back(std::numeric_limits<float>::infinity());
348	float32.push_back(-std::numeric_limits<float>::infinity());
349	// SNaN
350	float32.push_back(std::numeric_limits<float>::signaling_NaN());
351	float32.push_back(-std::numeric_limits<float>::signaling_NaN());
352	// QNaN
353	float32.push_back(std::numeric_limits<float>::quiet_NaN());
354	float32.push_back(-std::numeric_limits<float>::quiet_NaN());
355
356	// Denormalized 32-bit float matching 0 in 16-bit
357	float32.push_back(deFloatLdExp(1.f, -127));
358	float32.push_back(-deFloatLdExp(1.f, -127));
359
360	// Normalized 32-bit float matching 0 in 16-bit
361	float32.push_back(deFloatLdExp(1.f, -100));
362	float32.push_back(-deFloatLdExp(1.f, -100));
363	// Normalized 32-bit float with exact denormalized match in 16-bit
364	float32.push_back(deFloatLdExp(1.f, -24));  // 2e-24: minimum 16-bit positive denormalized
365	float32.push_back(-deFloatLdExp(1.f, -24)); // 2e-24: maximum 16-bit negative denormalized
366	// Normalized 32-bit float with exact normalized match in 16-bit
367	float32.push_back(deFloatLdExp(1.f, -14));  // 2e-14: minimum 16-bit positive normalized
368	float32.push_back(-deFloatLdExp(1.f, -14)); // 2e-14: maximum 16-bit negative normalized
369	// Normalized 32-bit float falling above half way within two 16-bit normalized
370	float32.push_back(bitwiseCast<float>(deUint32(0x3880ff00)));
371	float32.push_back(bitwiseCast<float>(deUint32(0xb880ff00)));
372	// Normalized 32-bit float falling exact half way within two 16-bit normalized
373	float32.push_back(bitwiseCast<float>(deUint32(0x38803000)));
374	float32.push_back(bitwiseCast<float>(deUint32(0xb8803000)));
375	// Some number
376	float32.push_back(0.28125f);
377	float32.push_back(-0.28125f);
378	// Normalized 32-bit float matching infinity in 16-bit
379	float32.push_back(deFloatLdExp(1.f, 100));
380	float32.push_back(-deFloatLdExp(1.f, 100));
381
382	const deUint32		numPicks	= static_cast<deUint32>(float32.size());
383
384	DE_ASSERT(count >= numPicks);
385	count -= numPicks;
386
387	for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
388		float32.push_back(rnd.getFloat());
389
390	return float32;
391}
392
393// IEEE-754 floating point numbers:
394// +--------+------+----------+-------------+
395// | binary | sign | exponent | significand |
396// +--------+------+----------+-------------+
397// | 16-bit |  1   |    5     |     10      |
398// +--------+------+----------+-------------+
399// | 32-bit |  1   |    8     |     23      |
400// +--------+------+----------+-------------+
401//
402// 16-bit floats:
403//
404// 0   000 00   00 0000 0001 (0x0001: 2e-24:         minimum positive denormalized)
405// 0   000 00   11 1111 1111 (0x03ff: 2e-14 - 2e-24: maximum positive denormalized)
406// 0   000 01   00 0000 0000 (0x0400: 2e-14:         minimum positive normalized)
407//
408// 0   000 00   00 0000 0000 (0x0000: +0)
409// 0   111 11   00 0000 0000 (0x7c00: +Inf)
410// 0   000 00   11 1111 0000 (0x03f0: +Denorm)
411// 0   000 01   00 0000 0001 (0x0401: +Norm)
412// 0   111 11   00 0000 1111 (0x7c0f: +SNaN)
413// 0   111 11   00 1111 0000 (0x7c0f: +QNaN)
414
415
416// Generate and return 16-bit floats and their corresponding 32-bit values.
417//
418// The first 14 number pairs are manually picked, while the rest are randomly generated.
419// Expected count to be at least 14 (numPicks).
420vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count)
421{
422	vector<deFloat16>	float16;
423
424	float16.reserve(count);
425
426	// Zero
427	float16.push_back(deUint16(0x0000));
428	float16.push_back(deUint16(0x8000));
429	// Infinity
430	float16.push_back(deUint16(0x7c00));
431	float16.push_back(deUint16(0xfc00));
432	// SNaN
433	float16.push_back(deUint16(0x7c0f));
434	float16.push_back(deUint16(0xfc0f));
435	// QNaN
436	float16.push_back(deUint16(0x7cf0));
437	float16.push_back(deUint16(0xfcf0));
438
439	// Denormalized
440	float16.push_back(deUint16(0x03f0));
441	float16.push_back(deUint16(0x83f0));
442	// Normalized
443	float16.push_back(deUint16(0x0401));
444	float16.push_back(deUint16(0x8401));
445	// Some normal number
446	float16.push_back(deUint16(0x14cb));
447	float16.push_back(deUint16(0x94cb));
448
449	const deUint32		numPicks	= static_cast<deUint32>(float16.size());
450
451	DE_ASSERT(count >= numPicks);
452	count -= numPicks;
453
454	for (deUint32 numIdx = 0; numIdx < count; ++numIdx)
455		float16.push_back(rnd.getUint16());
456
457	return float16;
458}
459
460void addCompute16bitStorageUniform16To32Group (tcu::TestCaseGroup* group)
461{
462	tcu::TestContext&				testCtx			= group->getTestContext();
463	de::Random						rnd				(deStringHash(group->getName()));
464	const int						numElements		= 128;
465
466	const StringTemplate			shaderTemplate	(
467		"OpCapability Shader\n"
468		"OpCapability ${capability}\n"
469		"OpExtension \"SPV_KHR_16bit_storage\"\n"
470		"OpMemoryModel Logical GLSL450\n"
471		"OpEntryPoint GLCompute %main \"main\" %id\n"
472		"OpExecutionMode %main LocalSize 1 1 1\n"
473		"OpDecorate %id BuiltIn GlobalInvocationId\n"
474
475		"${stride}"
476
477		"OpMemberDecorate %SSBO32 0 Offset 0\n"
478		"OpMemberDecorate %SSBO16 0 Offset 0\n"
479		"OpDecorate %SSBO32 BufferBlock\n"
480		"OpDecorate %SSBO16 ${storage}\n"
481		"OpDecorate %ssbo32 DescriptorSet 0\n"
482		"OpDecorate %ssbo16 DescriptorSet 0\n"
483		"OpDecorate %ssbo32 Binding 1\n"
484		"OpDecorate %ssbo16 Binding 0\n"
485
486		"${matrix_decor:opt}\n"
487
488		"%bool      = OpTypeBool\n"
489		"%void      = OpTypeVoid\n"
490		"%voidf     = OpTypeFunction %void\n"
491		"%u32       = OpTypeInt 32 0\n"
492		"%i32       = OpTypeInt 32 1\n"
493		"%f32       = OpTypeFloat 32\n"
494		"%uvec3     = OpTypeVector %u32 3\n"
495		"%fvec3     = OpTypeVector %f32 3\n"
496		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
497		"%i32ptr    = OpTypePointer Uniform %i32\n"
498		"%f32ptr    = OpTypePointer Uniform %f32\n"
499
500		"%zero      = OpConstant %i32 0\n"
501		"%c_i32_1   = OpConstant %i32 1\n"
502		"%c_i32_2   = OpConstant %i32 2\n"
503		"%c_i32_3   = OpConstant %i32 3\n"
504		"%c_i32_16  = OpConstant %i32 16\n"
505		"%c_i32_32  = OpConstant %i32 32\n"
506		"%c_i32_64  = OpConstant %i32 64\n"
507		"%c_i32_128 = OpConstant %i32 128\n"
508
509		"%i32arr    = OpTypeArray %i32 %c_i32_128\n"
510		"%f32arr    = OpTypeArray %f32 %c_i32_128\n"
511
512		"${types}\n"
513		"${matrix_types:opt}\n"
514
515		"%SSBO32    = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n"
516		"%SSBO16    = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n"
517		"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
518		"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
519		"%ssbo32    = OpVariable %up_SSBO32 Uniform\n"
520		"%ssbo16    = OpVariable %up_SSBO16 Uniform\n"
521
522		"%id        = OpVariable %uvec3ptr Input\n"
523
524		"%main      = OpFunction %void None %voidf\n"
525		"%label     = OpLabel\n"
526		"%idval     = OpLoad %uvec3 %id\n"
527		"%x         = OpCompositeExtract %u32 %idval 0\n"
528		"%inloc     = OpAccessChain %${base16}ptr %ssbo16 %zero %x ${index0:opt}\n"
529		"%val16     = OpLoad %${base16} %inloc\n"
530		"%val32     = ${convert} %${base32} %val16\n"
531		"%outloc    = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n"
532		"             OpStore %outloc %val32\n"
533		"${matrix_store:opt}\n"
534		"             OpReturn\n"
535		"             OpFunctionEnd\n");
536
537	{  // floats
538		const char										floatTypes[]	=
539			"%f16       = OpTypeFloat 16\n"
540			"%f16ptr    = OpTypePointer Uniform %f16\n"
541			"%f16arr    = OpTypeArray %f16 %c_i32_128\n"
542			"%v2f16     = OpTypeVector %f16 2\n"
543			"%v2f32     = OpTypeVector %f32 2\n"
544			"%v2f16ptr  = OpTypePointer Uniform %v2f16\n"
545			"%v2f32ptr  = OpTypePointer Uniform %v2f32\n"
546			"%v2f16arr  = OpTypeArray %v2f16 %c_i32_64\n"
547			"%v2f32arr  = OpTypeArray %v2f32 %c_i32_64\n";
548
549		struct CompositeType
550		{
551			const char*	name;
552			const char*	base32;
553			const char*	base16;
554			const char*	stride;
555			unsigned	count;
556		};
557
558		const CompositeType	cTypes[]	=
559		{
560			{"scalar",	"f32",		"f16",		"OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n",				numElements},
561			{"vector",	"v2f32",	"v2f16",	"OpDecorate %v2f32arr ArrayStride 8\nOpDecorate %v2f16arr ArrayStride 4\n",			numElements / 2},
562			{"matrix",	"v2f32",	"v2f16",	"OpDecorate %m4v2f32arr ArrayStride 32\nOpDecorate %m4v2f16arr ArrayStride 16\n",	numElements / 8},
563		};
564
565		vector<deFloat16>	float16Data			= getFloat16s(rnd, numElements);
566		vector<float>		float32Data;
567
568		float32Data.reserve(numElements);
569		for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
570			float32Data.push_back(deFloat16To32(float16Data[numIdx]));
571
572		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
573			for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
574			{
575				ComputeShaderSpec		spec;
576				map<string, string>		specs;
577				string					testName	= string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name + "_float";
578
579				specs["capability"]		= CAPABILITIES[capIdx].cap;
580				specs["storage"]		= CAPABILITIES[capIdx].decor;
581				specs["stride"]			= cTypes[tyIdx].stride;
582				specs["base32"]			= cTypes[tyIdx].base32;
583				specs["base16"]			= cTypes[tyIdx].base16;
584				specs["types"]			= floatTypes;
585				specs["convert"]		= "OpFConvert";
586
587				if (strcmp(cTypes[tyIdx].name, "matrix") == 0)
588				{
589					specs["index0"]			= "%zero";
590					specs["matrix_prefix"]	= "m4";
591					specs["matrix_types"]	=
592						"%m4v2f16 = OpTypeMatrix %v2f16 4\n"
593						"%m4v2f32 = OpTypeMatrix %v2f32 4\n"
594						"%m4v2f16arr = OpTypeArray %m4v2f16 %c_i32_16\n"
595						"%m4v2f32arr = OpTypeArray %m4v2f32 %c_i32_16\n";
596					specs["matrix_decor"]	=
597						"OpMemberDecorate %SSBO32 0 ColMajor\n"
598						"OpMemberDecorate %SSBO32 0 MatrixStride 8\n"
599						"OpMemberDecorate %SSBO16 0 ColMajor\n"
600						"OpMemberDecorate %SSBO16 0 MatrixStride 4\n";
601					specs["matrix_store"]	=
602						"%inloc_1  = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_1\n"
603						"%val16_1  = OpLoad %v2f16 %inloc_1\n"
604						"%val32_1  = OpFConvert %v2f32 %val16_1\n"
605						"%outloc_1 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_1\n"
606						"            OpStore %outloc_1 %val32_1\n"
607
608						"%inloc_2  = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_2\n"
609						"%val16_2  = OpLoad %v2f16 %inloc_2\n"
610						"%val32_2  = OpFConvert %v2f32 %val16_2\n"
611						"%outloc_2 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_2\n"
612						"            OpStore %outloc_2 %val32_2\n"
613
614						"%inloc_3  = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_3\n"
615						"%val16_3  = OpLoad %v2f16 %inloc_3\n"
616						"%val32_3  = OpFConvert %v2f32 %val16_3\n"
617						"%outloc_3 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_3\n"
618						"            OpStore %outloc_3 %val32_3\n";
619				}
620
621				spec.assembly			= shaderTemplate.specialize(specs);
622				spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
623				spec.verifyIO			= check32BitFloats;
624				spec.inputTypes[0]		= CAPABILITIES[capIdx].dtype;
625
626				spec.inputs.push_back(BufferSp(new Float16Buffer(float16Data)));
627				spec.outputs.push_back(BufferSp(new Float32Buffer(float32Data)));
628				spec.extensions.push_back("VK_KHR_16bit_storage");
629				spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
630
631				group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec));
632			}
633	}
634
635	{  // Integers
636		const char		sintTypes[]		=
637			"%i16       = OpTypeInt 16 1\n"
638			"%i16ptr    = OpTypePointer Uniform %i16\n"
639			"%i16arr    = OpTypeArray %i16 %c_i32_128\n"
640			"%v4i16     = OpTypeVector %i16 4\n"
641			"%v4i32     = OpTypeVector %i32 4\n"
642			"%v4i16ptr  = OpTypePointer Uniform %v4i16\n"
643			"%v4i32ptr  = OpTypePointer Uniform %v4i32\n"
644			"%v4i16arr  = OpTypeArray %v4i16 %c_i32_32\n"
645			"%v4i32arr  = OpTypeArray %v4i32 %c_i32_32\n";
646
647		const char		uintTypes[]		=
648			"%u16       = OpTypeInt 16 0\n"
649			"%u16ptr    = OpTypePointer Uniform %u16\n"
650			"%u32ptr    = OpTypePointer Uniform %u32\n"
651			"%u16arr    = OpTypeArray %u16 %c_i32_128\n"
652			"%u32arr    = OpTypeArray %u32 %c_i32_128\n"
653			"%v4u16     = OpTypeVector %u16 4\n"
654			"%v4u32     = OpTypeVector %u32 4\n"
655			"%v4u16ptr  = OpTypePointer Uniform %v4u16\n"
656			"%v4u32ptr  = OpTypePointer Uniform %v4u32\n"
657			"%v4u16arr  = OpTypeArray %v4u16 %c_i32_32\n"
658			"%v4u32arr  = OpTypeArray %v4u32 %c_i32_32\n";
659
660		struct CompositeType
661		{
662			const char*	name;
663			bool		isSigned;
664			const char* types;
665			const char*	base32;
666			const char*	base16;
667			const char* opcode;
668			const char*	stride;
669			unsigned	count;
670		};
671
672		const CompositeType	cTypes[]	=
673		{
674			{"scalar_sint",	true,	sintTypes,	"i32",		"i16",		"OpSConvert",	"OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n",			numElements},
675			{"scalar_uint",	false,	uintTypes,	"u32",		"u16",		"OpUConvert",	"OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n",			numElements},
676			{"vector_sint",	true,	sintTypes,	"v4i32",	"v4i16",	"OpSConvert",	"OpDecorate %v4i32arr ArrayStride 16\nOpDecorate %v4i16arr ArrayStride 8\n",	numElements / 4},
677			{"vector_uint",	false,	uintTypes,	"v4u32",	"v4u16",	"OpUConvert",	"OpDecorate %v4u32arr ArrayStride 16\nOpDecorate %v4u16arr ArrayStride 8\n",	numElements / 4},
678		};
679
680		vector<deInt16>	inputs			= getInt16s(rnd, numElements);
681		vector<deInt32> sOutputs;
682		vector<deInt32> uOutputs;
683		const deUint16	signBitMask		= 0x8000;
684		const deUint32	signExtendMask	= 0xffff0000;
685
686		sOutputs.reserve(inputs.size());
687		uOutputs.reserve(inputs.size());
688
689		for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
690		{
691			uOutputs.push_back(static_cast<deUint16>(inputs[numNdx]));
692			if (inputs[numNdx] & signBitMask)
693				sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask));
694			else
695				sOutputs.push_back(static_cast<deInt32>(inputs[numNdx]));
696		}
697
698		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
699			for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
700			{
701				ComputeShaderSpec		spec;
702				map<string, string>		specs;
703				string					testName	= string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name;
704
705				specs["capability"]		= CAPABILITIES[capIdx].cap;
706				specs["storage"]		= CAPABILITIES[capIdx].decor;
707				specs["stride"]			= cTypes[tyIdx].stride;
708				specs["base32"]			= cTypes[tyIdx].base32;
709				specs["base16"]			= cTypes[tyIdx].base16;
710				specs["types"]			= cTypes[tyIdx].types;
711				specs["convert"]		= cTypes[tyIdx].opcode;
712
713				spec.assembly			= shaderTemplate.specialize(specs);
714				spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
715				spec.inputTypes[0]		= CAPABILITIES[capIdx].dtype;
716
717				spec.inputs.push_back(BufferSp(new Int16Buffer(inputs)));
718				if (cTypes[tyIdx].isSigned)
719					spec.outputs.push_back(BufferSp(new Int32Buffer(sOutputs)));
720				else
721					spec.outputs.push_back(BufferSp(new Int32Buffer(uOutputs)));
722				spec.extensions.push_back("VK_KHR_16bit_storage");
723				spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
724
725				group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec));
726			}
727	}
728}
729
730void addCompute16bitStoragePushConstant16To32Group (tcu::TestCaseGroup* group)
731{
732	tcu::TestContext&				testCtx			= group->getTestContext();
733	de::Random						rnd				(deStringHash(group->getName()));
734	const int						numElements		= 64;
735
736	const StringTemplate			shaderTemplate	(
737		"OpCapability Shader\n"
738		"OpCapability StoragePushConstant16\n"
739		"OpExtension \"SPV_KHR_16bit_storage\"\n"
740		"OpMemoryModel Logical GLSL450\n"
741		"OpEntryPoint GLCompute %main \"main\" %id\n"
742		"OpExecutionMode %main LocalSize 1 1 1\n"
743		"OpDecorate %id BuiltIn GlobalInvocationId\n"
744
745		"${stride}"
746
747		"OpDecorate %PC16 Block\n"
748		"OpMemberDecorate %PC16 0 Offset 0\n"
749		"OpMemberDecorate %SSBO32 0 Offset 0\n"
750		"OpDecorate %SSBO32 BufferBlock\n"
751		"OpDecorate %ssbo32 DescriptorSet 0\n"
752		"OpDecorate %ssbo32 Binding 0\n"
753
754		"${matrix_decor:opt}\n"
755
756		"%bool      = OpTypeBool\n"
757		"%void      = OpTypeVoid\n"
758		"%voidf     = OpTypeFunction %void\n"
759		"%u32       = OpTypeInt 32 0\n"
760		"%i32       = OpTypeInt 32 1\n"
761		"%f32       = OpTypeFloat 32\n"
762		"%uvec3     = OpTypeVector %u32 3\n"
763		"%fvec3     = OpTypeVector %f32 3\n"
764		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
765		"%i32ptr    = OpTypePointer Uniform %i32\n"
766		"%f32ptr    = OpTypePointer Uniform %f32\n"
767
768		"%zero      = OpConstant %i32 0\n"
769		"%c_i32_1   = OpConstant %i32 1\n"
770		"%c_i32_8   = OpConstant %i32 8\n"
771		"%c_i32_16  = OpConstant %i32 16\n"
772		"%c_i32_32  = OpConstant %i32 32\n"
773		"%c_i32_64  = OpConstant %i32 64\n"
774
775		"%i32arr    = OpTypeArray %i32 %c_i32_64\n"
776		"%f32arr    = OpTypeArray %f32 %c_i32_64\n"
777
778		"${types}\n"
779		"${matrix_types:opt}\n"
780
781		"%PC16      = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n"
782		"%pp_PC16   = OpTypePointer PushConstant %PC16\n"
783		"%pc16      = OpVariable %pp_PC16 PushConstant\n"
784		"%SSBO32    = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n"
785		"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
786		"%ssbo32    = OpVariable %up_SSBO32 Uniform\n"
787
788		"%id        = OpVariable %uvec3ptr Input\n"
789
790		"%main      = OpFunction %void None %voidf\n"
791		"%label     = OpLabel\n"
792		"%idval     = OpLoad %uvec3 %id\n"
793		"%x         = OpCompositeExtract %u32 %idval 0\n"
794		"%inloc     = OpAccessChain %${base16}ptr %pc16 %zero %x ${index0:opt}\n"
795		"%val16     = OpLoad %${base16} %inloc\n"
796		"%val32     = ${convert} %${base32} %val16\n"
797		"%outloc    = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n"
798		"             OpStore %outloc %val32\n"
799		"${matrix_store:opt}\n"
800		"             OpReturn\n"
801		"             OpFunctionEnd\n");
802
803	{  // floats
804		const char										floatTypes[]	=
805			"%f16       = OpTypeFloat 16\n"
806			"%f16ptr    = OpTypePointer PushConstant %f16\n"
807			"%f16arr    = OpTypeArray %f16 %c_i32_64\n"
808			"%v4f16     = OpTypeVector %f16 4\n"
809			"%v4f32     = OpTypeVector %f32 4\n"
810			"%v4f16ptr  = OpTypePointer PushConstant %v4f16\n"
811			"%v4f32ptr  = OpTypePointer Uniform %v4f32\n"
812			"%v4f16arr  = OpTypeArray %v4f16 %c_i32_16\n"
813			"%v4f32arr  = OpTypeArray %v4f32 %c_i32_16\n";
814
815		struct CompositeType
816		{
817			const char*	name;
818			const char*	base32;
819			const char*	base16;
820			const char*	stride;
821			unsigned	count;
822		};
823
824		const CompositeType	cTypes[]	=
825		{
826			{"scalar",	"f32",		"f16",		"OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n",				numElements},
827			{"vector",	"v4f32",	"v4f16",	"OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n",		numElements / 4},
828			{"matrix",	"v4f32",	"v4f16",	"OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n",	numElements / 8},
829		};
830
831		vector<deFloat16>	float16Data			= getFloat16s(rnd, numElements);
832		vector<float>		float32Data;
833
834		float32Data.reserve(numElements);
835		for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
836			float32Data.push_back(deFloat16To32(float16Data[numIdx]));
837
838		for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
839		{
840			ComputeShaderSpec		spec;
841			map<string, string>		specs;
842			string					testName	= string(cTypes[tyIdx].name) + "_float";
843
844			specs["stride"]			= cTypes[tyIdx].stride;
845			specs["base32"]			= cTypes[tyIdx].base32;
846			specs["base16"]			= cTypes[tyIdx].base16;
847			specs["types"]			= floatTypes;
848			specs["convert"]		= "OpFConvert";
849
850			if (strcmp(cTypes[tyIdx].name, "matrix") == 0)
851			{
852				specs["index0"]			= "%zero";
853				specs["matrix_prefix"]	= "m2";
854				specs["matrix_types"]	=
855					"%m2v4f16 = OpTypeMatrix %v4f16 2\n"
856					"%m2v4f32 = OpTypeMatrix %v4f32 2\n"
857					"%m2v4f16arr = OpTypeArray %m2v4f16 %c_i32_8\n"
858					"%m2v4f32arr = OpTypeArray %m2v4f32 %c_i32_8\n";
859				specs["matrix_decor"]	=
860					"OpMemberDecorate %SSBO32 0 ColMajor\n"
861					"OpMemberDecorate %SSBO32 0 MatrixStride 16\n"
862					"OpMemberDecorate %PC16 0 ColMajor\n"
863					"OpMemberDecorate %PC16 0 MatrixStride 8\n";
864				specs["matrix_store"]	=
865					"%inloc_1  = OpAccessChain %v4f16ptr %pc16 %zero %x %c_i32_1\n"
866					"%val16_1  = OpLoad %v4f16 %inloc_1\n"
867					"%val32_1  = OpFConvert %v4f32 %val16_1\n"
868					"%outloc_1 = OpAccessChain %v4f32ptr %ssbo32 %zero %x %c_i32_1\n"
869					"            OpStore %outloc_1 %val32_1\n";
870			}
871
872			spec.assembly			= shaderTemplate.specialize(specs);
873			spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
874			spec.verifyIO			= check32BitFloats;
875			spec.pushConstants		= BufferSp(new Float16Buffer(float16Data));
876
877			spec.outputs.push_back(BufferSp(new Float32Buffer(float32Data)));
878			spec.extensions.push_back("VK_KHR_16bit_storage");
879			spec.requestedVulkanFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT;
880
881			group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec));
882		}
883	}
884	{  // integers
885		const char		sintTypes[]		=
886			"%i16       = OpTypeInt 16 1\n"
887			"%i16ptr    = OpTypePointer PushConstant %i16\n"
888			"%i16arr    = OpTypeArray %i16 %c_i32_64\n"
889			"%v2i16     = OpTypeVector %i16 2\n"
890			"%v2i32     = OpTypeVector %i32 2\n"
891			"%v2i16ptr  = OpTypePointer PushConstant %v2i16\n"
892			"%v2i32ptr  = OpTypePointer Uniform %v2i32\n"
893			"%v2i16arr  = OpTypeArray %v2i16 %c_i32_32\n"
894			"%v2i32arr  = OpTypeArray %v2i32 %c_i32_32\n";
895
896		const char		uintTypes[]		=
897			"%u16       = OpTypeInt 16 0\n"
898			"%u16ptr    = OpTypePointer PushConstant %u16\n"
899			"%u32ptr    = OpTypePointer Uniform %u32\n"
900			"%u16arr    = OpTypeArray %u16 %c_i32_64\n"
901			"%u32arr    = OpTypeArray %u32 %c_i32_64\n"
902			"%v2u16     = OpTypeVector %u16 2\n"
903			"%v2u32     = OpTypeVector %u32 2\n"
904			"%v2u16ptr  = OpTypePointer PushConstant %v2u16\n"
905			"%v2u32ptr  = OpTypePointer Uniform %v2u32\n"
906			"%v2u16arr  = OpTypeArray %v2u16 %c_i32_32\n"
907			"%v2u32arr  = OpTypeArray %v2u32 %c_i32_32\n";
908
909		struct CompositeType
910		{
911			const char*	name;
912			bool		isSigned;
913			const char* types;
914			const char*	base32;
915			const char*	base16;
916			const char* opcode;
917			const char*	stride;
918			unsigned	count;
919		};
920
921		const CompositeType	cTypes[]	=
922		{
923			{"scalar_sint",	true,	sintTypes,	"i32",		"i16",		"OpSConvert",	"OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n",		numElements},
924			{"scalar_uint",	false,	uintTypes,	"u32",		"u16",		"OpUConvert",	"OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n",		numElements},
925			{"vector_sint",	true,	sintTypes,	"v2i32",	"v2i16",	"OpSConvert",	"OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n",	numElements / 2},
926			{"vector_uint",	false,	uintTypes,	"v2u32",	"v2u16",	"OpUConvert",	"OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n",	numElements / 2},
927		};
928
929		vector<deInt16>	inputs			= getInt16s(rnd, numElements);
930		vector<deInt32> sOutputs;
931		vector<deInt32> uOutputs;
932		const deUint16	signBitMask		= 0x8000;
933		const deUint32	signExtendMask	= 0xffff0000;
934
935		sOutputs.reserve(inputs.size());
936		uOutputs.reserve(inputs.size());
937
938		for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
939		{
940			uOutputs.push_back(static_cast<deUint16>(inputs[numNdx]));
941			if (inputs[numNdx] & signBitMask)
942				sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask));
943			else
944				sOutputs.push_back(static_cast<deInt32>(inputs[numNdx]));
945		}
946
947		for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
948		{
949			ComputeShaderSpec		spec;
950			map<string, string>		specs;
951			const char*				testName	= cTypes[tyIdx].name;
952
953			specs["stride"]			= cTypes[tyIdx].stride;
954			specs["base32"]			= cTypes[tyIdx].base32;
955			specs["base16"]			= cTypes[tyIdx].base16;
956			specs["types"]			= cTypes[tyIdx].types;
957			specs["convert"]		= cTypes[tyIdx].opcode;
958
959			spec.assembly			= shaderTemplate.specialize(specs);
960			spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
961			spec.pushConstants		= BufferSp(new Int16Buffer(inputs));
962
963			if (cTypes[tyIdx].isSigned)
964				spec.outputs.push_back(BufferSp(new Int32Buffer(sOutputs)));
965			else
966				spec.outputs.push_back(BufferSp(new Int32Buffer(uOutputs)));
967			spec.extensions.push_back("VK_KHR_16bit_storage");
968			spec.requestedVulkanFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT;
969
970			group->addChild(new SpvAsmComputeShaderCase(testCtx, testName, testName, spec));
971		}
972	}
973}
974
975void addGraphics16BitStorageUniformInt32To16Group (tcu::TestCaseGroup* testGroup)
976{
977	de::Random							rnd					(deStringHash(testGroup->getName()));
978	map<string, string>					fragments;
979	const deUint32						numDataPoints		= 256;
980	RGBA								defaultColors[4];
981	GraphicsResources					resources;
982	vector<string>						extensions;
983	const StringTemplate				capabilities		("OpCapability ${cap}\n");
984	// inputs and outputs are declared to be vectors of signed integers.
985	// However, depending on the test, they may be interpreted as unsiged
986	// integers. That won't be a problem as long as we passed the bits
987	// in faithfully to the pipeline.
988	vector<deInt32>						inputs				= getInt32s(rnd, numDataPoints);
989	vector<deInt16>						outputs;
990
991	outputs.reserve(inputs.size());
992	for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
993		outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx]));
994
995	resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(inputs))));
996	resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int16Buffer(outputs))));
997
998	extensions.push_back("VK_KHR_16bit_storage");
999	fragments["extension"]	= "OpExtension \"SPV_KHR_16bit_storage\"";
1000
1001	getDefaultColors(defaultColors);
1002
1003	struct IntegerFacts
1004	{
1005		const char*	name;
1006		const char*	type32;
1007		const char*	type16;
1008		const char* opcode;
1009		const char*	isSigned;
1010	};
1011
1012	const IntegerFacts	intFacts[]		=
1013	{
1014		{"sint",	"%i32",		"%i16",		"OpSConvert",	"1"},
1015		{"uint",	"%u32",		"%u16",		"OpUConvert",	"0"},
1016	};
1017
1018	const StringTemplate	scalarPreMain(
1019			"${itype16} = OpTypeInt 16 ${signed}\n"
1020			"%c_i32_256 = OpConstant %i32 256\n"
1021			"   %up_i32 = OpTypePointer Uniform ${itype32}\n"
1022			"   %up_i16 = OpTypePointer Uniform ${itype16}\n"
1023			"   %ra_i32 = OpTypeArray ${itype32} %c_i32_256\n"
1024			"   %ra_i16 = OpTypeArray ${itype16} %c_i32_256\n"
1025			"   %SSBO32 = OpTypeStruct %ra_i32\n"
1026			"   %SSBO16 = OpTypeStruct %ra_i16\n"
1027			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1028			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1029			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
1030			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n");
1031
1032	const StringTemplate	scalarDecoration(
1033			"OpDecorate %ra_i32 ArrayStride 4\n"
1034			"OpDecorate %ra_i16 ArrayStride 2\n"
1035			"OpMemberDecorate %SSBO32 0 Offset 0\n"
1036			"OpMemberDecorate %SSBO16 0 Offset 0\n"
1037			"OpDecorate %SSBO32 ${indecor}\n"
1038			"OpDecorate %SSBO16 BufferBlock\n"
1039			"OpDecorate %ssbo32 DescriptorSet 0\n"
1040			"OpDecorate %ssbo16 DescriptorSet 0\n"
1041			"OpDecorate %ssbo32 Binding 0\n"
1042			"OpDecorate %ssbo16 Binding 1\n");
1043
1044	const StringTemplate	scalarTestFunc(
1045			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
1046			"    %param = OpFunctionParameter %v4f32\n"
1047
1048			"%entry = OpLabel\n"
1049			"    %i = OpVariable %fp_i32 Function\n"
1050			"         OpStore %i %c_i32_0\n"
1051			"         OpBranch %loop\n"
1052
1053			" %loop = OpLabel\n"
1054			"   %15 = OpLoad %i32 %i\n"
1055			"   %lt = OpSLessThan %bool %15 %c_i32_256\n"
1056			"         OpLoopMerge %merge %inc None\n"
1057			"         OpBranchConditional %lt %write %merge\n"
1058
1059			"%write = OpLabel\n"
1060			"   %30 = OpLoad %i32 %i\n"
1061			"  %src = OpAccessChain %up_i32 %ssbo32 %c_i32_0 %30\n"
1062			"%val32 = OpLoad ${itype32} %src\n"
1063			"%val16 = ${convert} ${itype16} %val32\n"
1064			"  %dst = OpAccessChain %up_i16 %ssbo16 %c_i32_0 %30\n"
1065			"         OpStore %dst %val16\n"
1066			"         OpBranch %inc\n"
1067
1068			"  %inc = OpLabel\n"
1069			"   %37 = OpLoad %i32 %i\n"
1070			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
1071			"         OpStore %i %39\n"
1072			"         OpBranch %loop\n"
1073
1074			"%merge = OpLabel\n"
1075			"         OpReturnValue %param\n"
1076
1077			"OpFunctionEnd\n");
1078
1079	const StringTemplate	vecPreMain(
1080			"${itype16} = OpTypeInt 16 ${signed}\n"
1081			" %c_i32_64 = OpConstant %i32 64\n"
1082			"%v4itype32 = OpTypeVector ${itype32} 4\n"
1083			"%v4itype16 = OpTypeVector ${itype16} 4\n"
1084			" %up_v4i32 = OpTypePointer Uniform %v4itype32\n"
1085			" %up_v4i16 = OpTypePointer Uniform %v4itype16\n"
1086			" %ra_v4i32 = OpTypeArray %v4itype32 %c_i32_64\n"
1087			" %ra_v4i16 = OpTypeArray %v4itype16 %c_i32_64\n"
1088			"   %SSBO32 = OpTypeStruct %ra_v4i32\n"
1089			"   %SSBO16 = OpTypeStruct %ra_v4i16\n"
1090			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1091			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1092			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
1093			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n");
1094
1095	const StringTemplate	vecDecoration(
1096			"OpDecorate %ra_v4i32 ArrayStride 16\n"
1097			"OpDecorate %ra_v4i16 ArrayStride 8\n"
1098			"OpMemberDecorate %SSBO32 0 Offset 0\n"
1099			"OpMemberDecorate %SSBO16 0 Offset 0\n"
1100			"OpDecorate %SSBO32 ${indecor}\n"
1101			"OpDecorate %SSBO16 BufferBlock\n"
1102			"OpDecorate %ssbo32 DescriptorSet 0\n"
1103			"OpDecorate %ssbo16 DescriptorSet 0\n"
1104			"OpDecorate %ssbo32 Binding 0\n"
1105			"OpDecorate %ssbo16 Binding 1\n");
1106
1107	const StringTemplate	vecTestFunc(
1108			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
1109			"    %param = OpFunctionParameter %v4f32\n"
1110
1111			"%entry = OpLabel\n"
1112			"    %i = OpVariable %fp_i32 Function\n"
1113			"         OpStore %i %c_i32_0\n"
1114			"         OpBranch %loop\n"
1115
1116			" %loop = OpLabel\n"
1117			"   %15 = OpLoad %i32 %i\n"
1118			"   %lt = OpSLessThan %bool %15 %c_i32_64\n"
1119			"         OpLoopMerge %merge %inc None\n"
1120			"         OpBranchConditional %lt %write %merge\n"
1121
1122			"%write = OpLabel\n"
1123			"   %30 = OpLoad %i32 %i\n"
1124			"  %src = OpAccessChain %up_v4i32 %ssbo32 %c_i32_0 %30\n"
1125			"%val32 = OpLoad %v4itype32 %src\n"
1126			"%val16 = ${convert} %v4itype16 %val32\n"
1127			"  %dst = OpAccessChain %up_v4i16 %ssbo16 %c_i32_0 %30\n"
1128			"         OpStore %dst %val16\n"
1129			"         OpBranch %inc\n"
1130
1131			"  %inc = OpLabel\n"
1132			"   %37 = OpLoad %i32 %i\n"
1133			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
1134			"         OpStore %i %39\n"
1135			"         OpBranch %loop\n"
1136
1137			"%merge = OpLabel\n"
1138			"         OpReturnValue %param\n"
1139
1140			"OpFunctionEnd\n");
1141
1142	struct Category
1143	{
1144		const char*				name;
1145		const StringTemplate&	preMain;
1146		const StringTemplate&	decoration;
1147		const StringTemplate&	testFunction;
1148	};
1149
1150	const Category		categories[]	=
1151	{
1152		{"scalar",	scalarPreMain,	scalarDecoration,	scalarTestFunc},
1153		{"vector",	vecPreMain,		vecDecoration,		vecTestFunc},
1154	};
1155
1156	for (deUint32 catIdx = 0; catIdx < DE_LENGTH_OF_ARRAY(categories); ++catIdx)
1157		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1158			for (deUint32 factIdx = 0; factIdx < DE_LENGTH_OF_ARRAY(intFacts); ++factIdx)
1159			{
1160				map<string, string>	specs;
1161				string				name		= string(CAPABILITIES[capIdx].name) + "_" + categories[catIdx].name + "_" + intFacts[factIdx].name;
1162
1163				specs["cap"]					= CAPABILITIES[capIdx].cap;
1164				specs["indecor"]				= CAPABILITIES[capIdx].decor;
1165				specs["itype32"]				= intFacts[factIdx].type32;
1166				specs["itype16"]				= intFacts[factIdx].type16;
1167				specs["signed"]					= intFacts[factIdx].isSigned;
1168				specs["convert"]				= intFacts[factIdx].opcode;
1169
1170				fragments["pre_main"]			= categories[catIdx].preMain.specialize(specs);
1171				fragments["testfun"]			= categories[catIdx].testFunction.specialize(specs);
1172				fragments["capability"]			= capabilities.specialize(specs);
1173				fragments["decoration"]			= categories[catIdx].decoration.specialize(specs);
1174
1175				resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
1176
1177				createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
1178			}
1179}
1180
1181void addCompute16bitStorageUniform32To16Group (tcu::TestCaseGroup* group)
1182{
1183	tcu::TestContext&				testCtx			= group->getTestContext();
1184	de::Random						rnd				(deStringHash(group->getName()));
1185	const int						numElements		= 128;
1186
1187	const StringTemplate			shaderTemplate	(
1188		"OpCapability Shader\n"
1189		"OpCapability ${capability}\n"
1190		"OpExtension \"SPV_KHR_16bit_storage\"\n"
1191		"OpMemoryModel Logical GLSL450\n"
1192		"OpEntryPoint GLCompute %main \"main\" %id\n"
1193		"OpExecutionMode %main LocalSize 1 1 1\n"
1194		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1195
1196		"${stride}"
1197
1198		"OpMemberDecorate %SSBO32 0 Offset 0\n"
1199		"OpMemberDecorate %SSBO16 0 Offset 0\n"
1200		"OpDecorate %SSBO32 ${storage}\n"
1201		"OpDecorate %SSBO16 BufferBlock\n"
1202		"OpDecorate %ssbo32 DescriptorSet 0\n"
1203		"OpDecorate %ssbo16 DescriptorSet 0\n"
1204		"OpDecorate %ssbo32 Binding 0\n"
1205		"OpDecorate %ssbo16 Binding 1\n"
1206
1207		"${matrix_decor:opt}\n"
1208
1209		"${rounding:opt}\n"
1210
1211		"%bool      = OpTypeBool\n"
1212		"%void      = OpTypeVoid\n"
1213		"%voidf     = OpTypeFunction %void\n"
1214		"%u32       = OpTypeInt 32 0\n"
1215		"%i32       = OpTypeInt 32 1\n"
1216		"%f32       = OpTypeFloat 32\n"
1217		"%uvec3     = OpTypeVector %u32 3\n"
1218		"%fvec3     = OpTypeVector %f32 3\n"
1219		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
1220		"%i32ptr    = OpTypePointer Uniform %i32\n"
1221		"%f32ptr    = OpTypePointer Uniform %f32\n"
1222
1223		"%zero      = OpConstant %i32 0\n"
1224		"%c_i32_1   = OpConstant %i32 1\n"
1225		"%c_i32_16  = OpConstant %i32 16\n"
1226		"%c_i32_32  = OpConstant %i32 32\n"
1227		"%c_i32_64  = OpConstant %i32 64\n"
1228		"%c_i32_128 = OpConstant %i32 128\n"
1229
1230		"%i32arr    = OpTypeArray %i32 %c_i32_128\n"
1231		"%f32arr    = OpTypeArray %f32 %c_i32_128\n"
1232
1233		"${types}\n"
1234		"${matrix_types:opt}\n"
1235
1236		"%SSBO32    = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n"
1237		"%SSBO16    = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n"
1238		"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1239		"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1240		"%ssbo32    = OpVariable %up_SSBO32 Uniform\n"
1241		"%ssbo16    = OpVariable %up_SSBO16 Uniform\n"
1242
1243		"%id        = OpVariable %uvec3ptr Input\n"
1244
1245		"%main      = OpFunction %void None %voidf\n"
1246		"%label     = OpLabel\n"
1247		"%idval     = OpLoad %uvec3 %id\n"
1248		"%x         = OpCompositeExtract %u32 %idval 0\n"
1249		"%inloc     = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n"
1250		"%val32     = OpLoad %${base32} %inloc\n"
1251		"%val16     = ${convert} %${base16} %val32\n"
1252		"%outloc    = OpAccessChain %${base16}ptr %ssbo16 %zero %x ${index0:opt}\n"
1253		"             OpStore %outloc %val16\n"
1254		"${matrix_store:opt}\n"
1255		"             OpReturn\n"
1256		"             OpFunctionEnd\n");
1257
1258	{  // Floats
1259		const char						floatTypes[]	=
1260			"%f16       = OpTypeFloat 16\n"
1261			"%f16ptr    = OpTypePointer Uniform %f16\n"
1262			"%f16arr    = OpTypeArray %f16 %c_i32_128\n"
1263			"%v4f16     = OpTypeVector %f16 4\n"
1264			"%v4f32     = OpTypeVector %f32 4\n"
1265			"%v4f16ptr  = OpTypePointer Uniform %v4f16\n"
1266			"%v4f32ptr  = OpTypePointer Uniform %v4f32\n"
1267			"%v4f16arr  = OpTypeArray %v4f16 %c_i32_32\n"
1268			"%v4f32arr  = OpTypeArray %v4f32 %c_i32_32\n";
1269
1270		struct RndMode
1271		{
1272			const char*				name;
1273			const char*				decor;
1274			ComputeVerifyIOFunc		func;
1275		};
1276
1277		const RndMode		rndModes[]		=
1278		{
1279			{"rtz",						"OpDecorate %val16  FPRoundingMode RTZ",	computeCheck16BitFloats<ROUNDINGMODE_RTZ>},
1280			{"rte",						"OpDecorate %val16  FPRoundingMode RTE",	computeCheck16BitFloats<ROUNDINGMODE_RTE>},
1281			{"unspecified_rnd_mode",	"",											computeCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>},
1282		};
1283
1284		struct CompositeType
1285		{
1286			const char*	name;
1287			const char*	base32;
1288			const char*	base16;
1289			const char*	stride;
1290			unsigned	count;
1291		};
1292
1293		const CompositeType	cTypes[]	=
1294		{
1295			{"scalar",	"f32",		"f16",		"OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n",				numElements},
1296			{"vector",	"v4f32",	"v4f16",	"OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n",		numElements / 4},
1297			{"matrix",	"v4f32",	"v4f16",	"OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n",	numElements / 8},
1298		};
1299
1300		vector<float>		float32Data			= getFloat32s(rnd, numElements);
1301		vector<deFloat16>	float16DummyData	(numElements, 0);
1302
1303		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1304			for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
1305				for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx)
1306				{
1307					ComputeShaderSpec		spec;
1308					map<string, string>		specs;
1309					string					testName	= string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name + "_float_" + rndModes[rndModeIdx].name;
1310
1311					specs["capability"]		= CAPABILITIES[capIdx].cap;
1312					specs["storage"]		= CAPABILITIES[capIdx].decor;
1313					specs["stride"]			= cTypes[tyIdx].stride;
1314					specs["base32"]			= cTypes[tyIdx].base32;
1315					specs["base16"]			= cTypes[tyIdx].base16;
1316					specs["rounding"]		= rndModes[rndModeIdx].decor;
1317					specs["types"]			= floatTypes;
1318					specs["convert"]		= "OpFConvert";
1319
1320					if (strcmp(cTypes[tyIdx].name, "matrix") == 0)
1321					{
1322						if (strcmp(rndModes[rndModeIdx].name, "rtz") == 0)
1323							specs["rounding"] += "\nOpDecorate %val16_1  FPRoundingMode RTZ\n";
1324						else if (strcmp(rndModes[rndModeIdx].name, "rte") == 0)
1325							specs["rounding"] += "\nOpDecorate %val16_1  FPRoundingMode RTE\n";
1326
1327						specs["index0"]			= "%zero";
1328						specs["matrix_prefix"]	= "m2";
1329						specs["matrix_types"]	=
1330							"%m2v4f16 = OpTypeMatrix %v4f16 2\n"
1331							"%m2v4f32 = OpTypeMatrix %v4f32 2\n"
1332							"%m2v4f16arr = OpTypeArray %m2v4f16 %c_i32_16\n"
1333							"%m2v4f32arr = OpTypeArray %m2v4f32 %c_i32_16\n";
1334						specs["matrix_decor"]	=
1335							"OpMemberDecorate %SSBO32 0 ColMajor\n"
1336							"OpMemberDecorate %SSBO32 0 MatrixStride 16\n"
1337							"OpMemberDecorate %SSBO16 0 ColMajor\n"
1338							"OpMemberDecorate %SSBO16 0 MatrixStride 8\n";
1339						specs["matrix_store"]	=
1340							"%inloc_1  = OpAccessChain %v4f32ptr %ssbo32 %zero %x %c_i32_1\n"
1341							"%val32_1  = OpLoad %v4f32 %inloc_1\n"
1342							"%val16_1  = OpFConvert %v4f16 %val32_1\n"
1343							"%outloc_1 = OpAccessChain %v4f16ptr %ssbo16 %zero %x %c_i32_1\n"
1344							"            OpStore %outloc_1 %val16_1\n";
1345					}
1346
1347					spec.assembly			= shaderTemplate.specialize(specs);
1348					spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
1349					spec.verifyIO			= rndModes[rndModeIdx].func;
1350					spec.inputTypes[0]		= CAPABILITIES[capIdx].dtype;
1351
1352					spec.inputs.push_back(BufferSp(new Float32Buffer(float32Data)));
1353					// We provided a custom verifyIO in the above in which inputs will be used for checking.
1354					// So put dummy data in the expected values.
1355					spec.outputs.push_back(BufferSp(new Float16Buffer(float16DummyData)));
1356					spec.extensions.push_back("VK_KHR_16bit_storage");
1357					spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
1358
1359					group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec));
1360				}
1361	}
1362
1363	{  // Integers
1364		const char		sintTypes[]	=
1365			"%i16       = OpTypeInt 16 1\n"
1366			"%i16ptr    = OpTypePointer Uniform %i16\n"
1367			"%i16arr    = OpTypeArray %i16 %c_i32_128\n"
1368			"%v2i16     = OpTypeVector %i16 2\n"
1369			"%v2i32     = OpTypeVector %i32 2\n"
1370			"%v2i16ptr  = OpTypePointer Uniform %v2i16\n"
1371			"%v2i32ptr  = OpTypePointer Uniform %v2i32\n"
1372			"%v2i16arr  = OpTypeArray %v2i16 %c_i32_64\n"
1373			"%v2i32arr  = OpTypeArray %v2i32 %c_i32_64\n";
1374
1375		const char		uintTypes[]	=
1376			"%u16       = OpTypeInt 16 0\n"
1377			"%u16ptr    = OpTypePointer Uniform %u16\n"
1378			"%u32ptr    = OpTypePointer Uniform %u32\n"
1379			"%u16arr    = OpTypeArray %u16 %c_i32_128\n"
1380			"%u32arr    = OpTypeArray %u32 %c_i32_128\n"
1381			"%v2u16     = OpTypeVector %u16 2\n"
1382			"%v2u32     = OpTypeVector %u32 2\n"
1383			"%v2u16ptr  = OpTypePointer Uniform %v2u16\n"
1384			"%v2u32ptr  = OpTypePointer Uniform %v2u32\n"
1385			"%v2u16arr  = OpTypeArray %v2u16 %c_i32_64\n"
1386			"%v2u32arr  = OpTypeArray %v2u32 %c_i32_64\n";
1387
1388		struct CompositeType
1389		{
1390			const char*	name;
1391			const char* types;
1392			const char*	base32;
1393			const char*	base16;
1394			const char* opcode;
1395			const char*	stride;
1396			unsigned	count;
1397		};
1398
1399		const CompositeType	cTypes[]	=
1400		{
1401			{"scalar_sint",	sintTypes,	"i32",		"i16",		"OpSConvert",	"OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n",		numElements},
1402			{"scalar_uint",	uintTypes,	"u32",		"u16",		"OpUConvert",	"OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n",		numElements},
1403			{"vector_sint",	sintTypes,	"v2i32",	"v2i16",	"OpSConvert",	"OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n",	numElements / 2},
1404			{"vector_uint",	uintTypes,	"v2u32",	"v2u16",	"OpUConvert",	"OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n",	numElements / 2},
1405		};
1406
1407		vector<deInt32>	inputs			= getInt32s(rnd, numElements);
1408		vector<deInt16> outputs;
1409
1410		outputs.reserve(inputs.size());
1411		for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
1412			outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx]));
1413
1414		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1415			for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx)
1416			{
1417				ComputeShaderSpec		spec;
1418				map<string, string>		specs;
1419				string					testName	= string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name;
1420
1421				specs["capability"]		= CAPABILITIES[capIdx].cap;
1422				specs["storage"]		= CAPABILITIES[capIdx].decor;
1423				specs["stride"]			= cTypes[tyIdx].stride;
1424				specs["base32"]			= cTypes[tyIdx].base32;
1425				specs["base16"]			= cTypes[tyIdx].base16;
1426				specs["types"]			= cTypes[tyIdx].types;
1427				specs["convert"]		= cTypes[tyIdx].opcode;
1428
1429				spec.assembly			= shaderTemplate.specialize(specs);
1430				spec.numWorkGroups		= IVec3(cTypes[tyIdx].count, 1, 1);
1431				spec.inputTypes[0]		= CAPABILITIES[capIdx].dtype;
1432
1433				spec.inputs.push_back(BufferSp(new Int32Buffer(inputs)));
1434				spec.outputs.push_back(BufferSp(new Int16Buffer(outputs)));
1435				spec.extensions.push_back("VK_KHR_16bit_storage");
1436				spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
1437
1438				group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec));
1439			}
1440	}
1441}
1442
1443void addGraphics16BitStorageUniformFloat32To16Group (tcu::TestCaseGroup* testGroup)
1444{
1445	de::Random							rnd					(deStringHash(testGroup->getName()));
1446	map<string, string>					fragments;
1447	GraphicsResources					resources;
1448	vector<string>						extensions;
1449	const deUint32						numDataPoints		= 256;
1450	RGBA								defaultColors[4];
1451	vector<float>						float32Data			= getFloat32s(rnd, numDataPoints);
1452	vector<deFloat16>					float16DummyData	(numDataPoints, 0);
1453	const StringTemplate				capabilities		("OpCapability ${cap}\n");
1454
1455	resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data))));
1456	// We use a custom verifyIO to check the result via computing directly from inputs; the contents in outputs do not matter.
1457	resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float16Buffer(float16DummyData))));
1458
1459	extensions.push_back("VK_KHR_16bit_storage");
1460	fragments["extension"]	= "OpExtension \"SPV_KHR_16bit_storage\"";
1461
1462	struct RndMode
1463	{
1464		const char*				name;
1465		const char*				decor;
1466		GraphicsVerifyIOFunc	f;
1467	};
1468
1469	getDefaultColors(defaultColors);
1470
1471	{  // scalar cases
1472		fragments["pre_main"]				=
1473			"      %f16 = OpTypeFloat 16\n"
1474			"%c_i32_256 = OpConstant %i32 256\n"
1475			"   %up_f32 = OpTypePointer Uniform %f32\n"
1476			"   %up_f16 = OpTypePointer Uniform %f16\n"
1477			"   %ra_f32 = OpTypeArray %f32 %c_i32_256\n"
1478			"   %ra_f16 = OpTypeArray %f16 %c_i32_256\n"
1479			"   %SSBO32 = OpTypeStruct %ra_f32\n"
1480			"   %SSBO16 = OpTypeStruct %ra_f16\n"
1481			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1482			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1483			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
1484			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
1485
1486		const StringTemplate decoration		(
1487			"OpDecorate %ra_f32 ArrayStride 4\n"
1488			"OpDecorate %ra_f16 ArrayStride 2\n"
1489			"OpMemberDecorate %SSBO32 0 Offset 0\n"
1490			"OpMemberDecorate %SSBO16 0 Offset 0\n"
1491			"OpDecorate %SSBO32 ${indecor}\n"
1492			"OpDecorate %SSBO16 BufferBlock\n"
1493			"OpDecorate %ssbo32 DescriptorSet 0\n"
1494			"OpDecorate %ssbo16 DescriptorSet 0\n"
1495			"OpDecorate %ssbo32 Binding 0\n"
1496			"OpDecorate %ssbo16 Binding 1\n"
1497			"${rounddecor}\n");
1498
1499		fragments["testfun"]				=
1500			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
1501			"    %param = OpFunctionParameter %v4f32\n"
1502
1503			"%entry = OpLabel\n"
1504			"    %i = OpVariable %fp_i32 Function\n"
1505			"         OpStore %i %c_i32_0\n"
1506			"         OpBranch %loop\n"
1507
1508			" %loop = OpLabel\n"
1509			"   %15 = OpLoad %i32 %i\n"
1510			"   %lt = OpSLessThan %bool %15 %c_i32_256\n"
1511			"         OpLoopMerge %merge %inc None\n"
1512			"         OpBranchConditional %lt %write %merge\n"
1513
1514			"%write = OpLabel\n"
1515			"   %30 = OpLoad %i32 %i\n"
1516			"  %src = OpAccessChain %up_f32 %ssbo32 %c_i32_0 %30\n"
1517			"%val32 = OpLoad %f32 %src\n"
1518			"%val16 = OpFConvert %f16 %val32\n"
1519			"  %dst = OpAccessChain %up_f16 %ssbo16 %c_i32_0 %30\n"
1520			"         OpStore %dst %val16\n"
1521			"         OpBranch %inc\n"
1522
1523			"  %inc = OpLabel\n"
1524			"   %37 = OpLoad %i32 %i\n"
1525			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
1526			"         OpStore %i %39\n"
1527			"         OpBranch %loop\n"
1528
1529			"%merge = OpLabel\n"
1530			"         OpReturnValue %param\n"
1531
1532			"OpFunctionEnd\n";
1533
1534		const RndMode	rndModes[] =
1535		{
1536			{"rtz",						"OpDecorate %val16  FPRoundingMode RTZ",	graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>},
1537			{"rte",						"OpDecorate %val16  FPRoundingMode RTE",	graphicsCheck16BitFloats<ROUNDINGMODE_RTE>},
1538			{"unspecified_rnd_mode",	"",											graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>},
1539		};
1540
1541		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1542			for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx)
1543			{
1544				map<string, string>	specs;
1545				string				testName	= string(CAPABILITIES[capIdx].name) + "_scalar_float_" + rndModes[rndModeIdx].name;
1546
1547				specs["cap"]					= CAPABILITIES[capIdx].cap;
1548				specs["indecor"]				= CAPABILITIES[capIdx].decor;
1549				specs["rounddecor"]				= rndModes[rndModeIdx].decor;
1550
1551				fragments["capability"]			= capabilities.specialize(specs);
1552				fragments["decoration"]			= decoration.specialize(specs);
1553
1554				resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
1555				resources.verifyIO				= rndModes[rndModeIdx].f;
1556
1557
1558				createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
1559			}
1560	}
1561
1562	{  // vector cases
1563		fragments["pre_main"]				=
1564			"      %f16 = OpTypeFloat 16\n"
1565			" %c_i32_64 = OpConstant %i32 64\n"
1566			"	 %v4f16 = OpTypeVector %f16 4\n"
1567			" %up_v4f32 = OpTypePointer Uniform %v4f32\n"
1568			" %up_v4f16 = OpTypePointer Uniform %v4f16\n"
1569			" %ra_v4f32 = OpTypeArray %v4f32 %c_i32_64\n"
1570			" %ra_v4f16 = OpTypeArray %v4f16 %c_i32_64\n"
1571			"   %SSBO32 = OpTypeStruct %ra_v4f32\n"
1572			"   %SSBO16 = OpTypeStruct %ra_v4f16\n"
1573			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1574			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1575			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
1576			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
1577
1578		const StringTemplate decoration		(
1579			"OpDecorate %ra_v4f32 ArrayStride 16\n"
1580			"OpDecorate %ra_v4f16 ArrayStride 8\n"
1581			"OpMemberDecorate %SSBO32 0 Offset 0\n"
1582			"OpMemberDecorate %SSBO16 0 Offset 0\n"
1583			"OpDecorate %SSBO32 ${indecor}\n"
1584			"OpDecorate %SSBO16 BufferBlock\n"
1585			"OpDecorate %ssbo32 DescriptorSet 0\n"
1586			"OpDecorate %ssbo16 DescriptorSet 0\n"
1587			"OpDecorate %ssbo32 Binding 0\n"
1588			"OpDecorate %ssbo16 Binding 1\n"
1589			"${rounddecor}\n");
1590
1591		// ssbo16[] <- convert ssbo32[] to 16bit float
1592		fragments["testfun"]				=
1593			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
1594			"    %param = OpFunctionParameter %v4f32\n"
1595
1596			"%entry = OpLabel\n"
1597			"    %i = OpVariable %fp_i32 Function\n"
1598			"         OpStore %i %c_i32_0\n"
1599			"         OpBranch %loop\n"
1600
1601			" %loop = OpLabel\n"
1602			"   %15 = OpLoad %i32 %i\n"
1603			"   %lt = OpSLessThan %bool %15 %c_i32_64\n"
1604			"         OpLoopMerge %merge %inc None\n"
1605			"         OpBranchConditional %lt %write %merge\n"
1606
1607			"%write = OpLabel\n"
1608			"   %30 = OpLoad %i32 %i\n"
1609			"  %src = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30\n"
1610			"%val32 = OpLoad %v4f32 %src\n"
1611			"%val16 = OpFConvert %v4f16 %val32\n"
1612			"  %dst = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30\n"
1613			"         OpStore %dst %val16\n"
1614			"         OpBranch %inc\n"
1615
1616			"  %inc = OpLabel\n"
1617			"   %37 = OpLoad %i32 %i\n"
1618			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
1619			"         OpStore %i %39\n"
1620			"         OpBranch %loop\n"
1621
1622			"%merge = OpLabel\n"
1623			"         OpReturnValue %param\n"
1624
1625			"OpFunctionEnd\n";
1626
1627		const RndMode	rndModes[] =
1628		{
1629			{"rtz",						"OpDecorate %val16  FPRoundingMode RTZ",	graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>},
1630			{"rte",						"OpDecorate %val16  FPRoundingMode RTE",	graphicsCheck16BitFloats<ROUNDINGMODE_RTE>},
1631			{"unspecified_rnd_mode",	"",											graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>},
1632		};
1633
1634		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1635			for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx)
1636			{
1637				map<string, string>	specs;
1638				string				testName	= string(CAPABILITIES[capIdx].name) + "_vector_float_" + rndModes[rndModeIdx].name;
1639
1640				specs["cap"]					= CAPABILITIES[capIdx].cap;
1641				specs["indecor"]				= CAPABILITIES[capIdx].decor;
1642				specs["rounddecor"]				= rndModes[rndModeIdx].decor;
1643
1644				fragments["capability"]			= capabilities.specialize(specs);
1645				fragments["decoration"]			= decoration.specialize(specs);
1646
1647				resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
1648				resources.verifyIO				= rndModes[rndModeIdx].f;
1649
1650
1651				createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
1652			}
1653	}
1654
1655	{  // matrix cases
1656		fragments["pre_main"]				=
1657			"       %f16 = OpTypeFloat 16\n"
1658			"  %c_i32_16 = OpConstant %i32 16\n"
1659			"     %v4f16 = OpTypeVector %f16 4\n"
1660			"   %m4x4f32 = OpTypeMatrix %v4f32 4\n"
1661			"   %m4x4f16 = OpTypeMatrix %v4f16 4\n"
1662			"  %up_v4f32 = OpTypePointer Uniform %v4f32\n"
1663			"  %up_v4f16 = OpTypePointer Uniform %v4f16\n"
1664			"%a16m4x4f32 = OpTypeArray %m4x4f32 %c_i32_16\n"
1665			"%a16m4x4f16 = OpTypeArray %m4x4f16 %c_i32_16\n"
1666			"    %SSBO32 = OpTypeStruct %a16m4x4f32\n"
1667			"    %SSBO16 = OpTypeStruct %a16m4x4f16\n"
1668			" %up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
1669			" %up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
1670			"    %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
1671			"    %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
1672
1673		const StringTemplate decoration		(
1674			"OpDecorate %a16m4x4f32 ArrayStride 64\n"
1675			"OpDecorate %a16m4x4f16 ArrayStride 32\n"
1676			"OpMemberDecorate %SSBO32 0 Offset 0\n"
1677			"OpMemberDecorate %SSBO32 0 ColMajor\n"
1678			"OpMemberDecorate %SSBO32 0 MatrixStride 16\n"
1679			"OpMemberDecorate %SSBO16 0 Offset 0\n"
1680			"OpMemberDecorate %SSBO16 0 ColMajor\n"
1681			"OpMemberDecorate %SSBO16 0 MatrixStride 8\n"
1682			"OpDecorate %SSBO32 ${indecor}\n"
1683			"OpDecorate %SSBO16 BufferBlock\n"
1684			"OpDecorate %ssbo32 DescriptorSet 0\n"
1685			"OpDecorate %ssbo16 DescriptorSet 0\n"
1686			"OpDecorate %ssbo32 Binding 0\n"
1687			"OpDecorate %ssbo16 Binding 1\n"
1688			"${rounddecor}\n");
1689
1690		fragments["testfun"]				=
1691			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
1692			"    %param = OpFunctionParameter %v4f32\n"
1693
1694			"%entry = OpLabel\n"
1695			"    %i = OpVariable %fp_i32 Function\n"
1696			"         OpStore %i %c_i32_0\n"
1697			"         OpBranch %loop\n"
1698
1699			" %loop = OpLabel\n"
1700			"   %15 = OpLoad %i32 %i\n"
1701			"   %lt = OpSLessThan %bool %15 %c_i32_16\n"
1702			"         OpLoopMerge %merge %inc None\n"
1703			"         OpBranchConditional %lt %write %merge\n"
1704
1705			"  %write = OpLabel\n"
1706			"     %30 = OpLoad %i32 %i\n"
1707			"  %src_0 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_0\n"
1708			"  %src_1 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_1\n"
1709			"  %src_2 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_2\n"
1710			"  %src_3 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_3\n"
1711			"%val32_0 = OpLoad %v4f32 %src_0\n"
1712			"%val32_1 = OpLoad %v4f32 %src_1\n"
1713			"%val32_2 = OpLoad %v4f32 %src_2\n"
1714			"%val32_3 = OpLoad %v4f32 %src_3\n"
1715			"%val16_0 = OpFConvert %v4f16 %val32_0\n"
1716			"%val16_1 = OpFConvert %v4f16 %val32_1\n"
1717			"%val16_2 = OpFConvert %v4f16 %val32_2\n"
1718			"%val16_3 = OpFConvert %v4f16 %val32_3\n"
1719			"  %dst_0 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_0\n"
1720			"  %dst_1 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_1\n"
1721			"  %dst_2 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_2\n"
1722			"  %dst_3 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_3\n"
1723			"           OpStore %dst_0 %val16_0\n"
1724			"           OpStore %dst_1 %val16_1\n"
1725			"           OpStore %dst_2 %val16_2\n"
1726			"           OpStore %dst_3 %val16_3\n"
1727			"           OpBranch %inc\n"
1728
1729			"  %inc = OpLabel\n"
1730			"   %37 = OpLoad %i32 %i\n"
1731			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
1732			"         OpStore %i %39\n"
1733			"         OpBranch %loop\n"
1734
1735			"%merge = OpLabel\n"
1736			"         OpReturnValue %param\n"
1737
1738			"OpFunctionEnd\n";
1739
1740		const RndMode	rndModes[] =
1741		{
1742			{"rte",						"OpDecorate %val16_0  FPRoundingMode RTE\nOpDecorate %val16_1  FPRoundingMode RTE\nOpDecorate %val16_2  FPRoundingMode RTE\nOpDecorate %val16_3  FPRoundingMode RTE",	graphicsCheck16BitFloats<ROUNDINGMODE_RTE>},
1743			{"rtz",						"OpDecorate %val16_0  FPRoundingMode RTZ\nOpDecorate %val16_1  FPRoundingMode RTZ\nOpDecorate %val16_2  FPRoundingMode RTZ\nOpDecorate %val16_3  FPRoundingMode RTZ",	graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>},
1744			{"unspecified_rnd_mode",	"",																																										graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>},
1745		};
1746
1747		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
1748			for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx)
1749			{
1750				map<string, string>	specs;
1751				string				testName	= string(CAPABILITIES[capIdx].name) + "_matrix_float_" + rndModes[rndModeIdx].name;
1752
1753				specs["cap"]					= CAPABILITIES[capIdx].cap;
1754				specs["indecor"]				= CAPABILITIES[capIdx].decor;
1755				specs["rounddecor"]				= rndModes[rndModeIdx].decor;
1756
1757				fragments["capability"]			= capabilities.specialize(specs);
1758				fragments["decoration"]			= decoration.specialize(specs);
1759
1760				resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
1761				resources.verifyIO				= rndModes[rndModeIdx].f;
1762
1763
1764				createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
1765			}
1766	}
1767}
1768
1769void addGraphics16BitStorageInputOutputFloat32To16Group (tcu::TestCaseGroup* testGroup)
1770{
1771	de::Random			rnd					(deStringHash(testGroup->getName()));
1772	RGBA				defaultColors[4];
1773	vector<string>		extensions;
1774	map<string, string>	fragments			= passthruFragments();
1775	const deUint32		numDataPoints		= 64;
1776	vector<float>		float32Data			= getFloat32s(rnd, numDataPoints);
1777
1778	extensions.push_back("VK_KHR_16bit_storage");
1779
1780	fragments["capability"]				= "OpCapability StorageInputOutput16\n";
1781	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"\n";
1782
1783	getDefaultColors(defaultColors);
1784
1785	struct RndMode
1786	{
1787		const char*				name;
1788		const char*				decor;
1789		RoundingModeFlags		flags;
1790	};
1791
1792	const RndMode		rndModes[]		=
1793	{
1794		{"rtz",						"OpDecorate %ret  FPRoundingMode RTZ",	ROUNDINGMODE_RTZ},
1795		{"rte",						"OpDecorate %ret  FPRoundingMode RTE",	ROUNDINGMODE_RTE},
1796		{"unspecified_rnd_mode",	"",										RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)},
1797	};
1798
1799	struct Case
1800	{
1801		const char*	name;
1802		const char*	interfaceOpFunc;
1803		const char*	preMain;
1804		const char*	inputType;
1805		const char*	outputType;
1806		deUint32	numPerCase;
1807		deUint32	numElements;
1808	};
1809
1810	const Case	cases[]		=
1811	{
1812		{ // Scalar cases
1813			"scalar",
1814
1815			"%interface_op_func = OpFunction %f16 None %f16_f32_function\n"
1816			"        %io_param1 = OpFunctionParameter %f32\n"
1817			"            %entry = OpLabel\n"
1818			"			   %ret = OpFConvert %f16 %io_param1\n"
1819			"                     OpReturnValue %ret\n"
1820			"                     OpFunctionEnd\n",
1821
1822			"             %f16 = OpTypeFloat 16\n"
1823			"          %op_f16 = OpTypePointer Output %f16\n"
1824			"           %a3f16 = OpTypeArray %f16 %c_i32_3\n"
1825			"        %op_a3f16 = OpTypePointer Output %a3f16\n"
1826			"%f16_f32_function = OpTypeFunction %f16 %f32\n"
1827			"           %a3f32 = OpTypeArray %f32 %c_i32_3\n"
1828			"        %ip_a3f32 = OpTypePointer Input %a3f32\n",
1829
1830			"f32",
1831			"f16",
1832			4,
1833			1,
1834		},
1835		{ // Vector cases
1836			"vector",
1837
1838			"%interface_op_func = OpFunction %v2f16 None %v2f16_v2f32_function\n"
1839			"        %io_param1 = OpFunctionParameter %v2f32\n"
1840			"            %entry = OpLabel\n"
1841			"			   %ret = OpFConvert %v2f16 %io_param1\n"
1842			"                     OpReturnValue %ret\n"
1843			"                     OpFunctionEnd\n",
1844
1845			"                 %f16 = OpTypeFloat 16\n"
1846			"               %v2f16 = OpTypeVector %f16 2\n"
1847			"            %op_v2f16 = OpTypePointer Output %v2f16\n"
1848			"             %a3v2f16 = OpTypeArray %v2f16 %c_i32_3\n"
1849			"          %op_a3v2f16 = OpTypePointer Output %a3v2f16\n"
1850			"%v2f16_v2f32_function = OpTypeFunction %v2f16 %v2f32\n"
1851			"             %a3v2f32 = OpTypeArray %v2f32 %c_i32_3\n"
1852			"          %ip_a3v2f32 = OpTypePointer Input %a3v2f32\n",
1853
1854			"v2f32",
1855			"v2f16",
1856			2 * 4,
1857			2,
1858		}
1859	};
1860
1861	VulkanFeatures	requiredFeatures;
1862	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT;
1863
1864	for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx)
1865		for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx)
1866		{
1867			fragments["interface_op_func"]	= cases[caseIdx].interfaceOpFunc;
1868			fragments["pre_main"]			= cases[caseIdx].preMain;
1869			fragments["decoration"]			= rndModes[rndModeIdx].decor;
1870
1871			fragments["input_type"]			= cases[caseIdx].inputType;
1872			fragments["output_type"]		= cases[caseIdx].outputType;
1873
1874			GraphicsInterfaces	interfaces;
1875			const deUint32		numPerCase	= cases[caseIdx].numPerCase;
1876			vector<float>		subInputs	(numPerCase);
1877			vector<deFloat16>	subOutputs	(numPerCase);
1878
1879			// The pipeline need this to call compare16BitFloat() when checking the result.
1880			interfaces.setRoundingMode(rndModes[rndModeIdx].flags);
1881
1882			for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx)
1883			{
1884				string			testName	= string(cases[caseIdx].name) + numberToString(caseNdx) + "_" + rndModes[rndModeIdx].name;
1885
1886				for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx)
1887				{
1888					subInputs[numNdx]	= float32Data[caseNdx * numPerCase + numNdx];
1889					// We derive the expected result from inputs directly in the graphics pipeline.
1890					subOutputs[numNdx]	= 0;
1891				}
1892				interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT32), BufferSp(new Float32Buffer(subInputs))),
1893										  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT16), BufferSp(new Float16Buffer(subOutputs))));
1894				createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures);
1895			}
1896		}
1897}
1898
1899void addGraphics16BitStorageInputOutputFloat16To32Group (tcu::TestCaseGroup* testGroup)
1900{
1901	de::Random				rnd					(deStringHash(testGroup->getName()));
1902	RGBA					defaultColors[4];
1903	vector<string>			extensions;
1904	map<string, string>		fragments			= passthruFragments();
1905	const deUint32			numDataPoints		= 64;
1906	vector<deFloat16>		float16Data			(getFloat16s(rnd, numDataPoints));
1907	vector<float>			float32Data;
1908
1909	float32Data.reserve(numDataPoints);
1910	for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx)
1911		float32Data.push_back(deFloat16To32(float16Data[numIdx]));
1912
1913	extensions.push_back("VK_KHR_16bit_storage");
1914
1915	fragments["capability"]				= "OpCapability StorageInputOutput16\n";
1916	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"\n";
1917
1918	getDefaultColors(defaultColors);
1919
1920	struct Case
1921	{
1922		const char*	name;
1923		const char*	interfaceOpFunc;
1924		const char*	preMain;
1925		const char*	inputType;
1926		const char*	outputType;
1927		deUint32	numPerCase;
1928		deUint32	numElements;
1929	};
1930
1931	Case	cases[]		=
1932	{
1933		{ // Scalar cases
1934			"scalar",
1935
1936			"%interface_op_func = OpFunction %f32 None %f32_f16_function\n"
1937			"        %io_param1 = OpFunctionParameter %f16\n"
1938			"            %entry = OpLabel\n"
1939			"			   %ret = OpFConvert %f32 %io_param1\n"
1940			"                     OpReturnValue %ret\n"
1941			"                     OpFunctionEnd\n",
1942
1943			"             %f16 = OpTypeFloat 16\n"
1944			"          %ip_f16 = OpTypePointer Input %f16\n"
1945			"           %a3f16 = OpTypeArray %f16 %c_i32_3\n"
1946			"        %ip_a3f16 = OpTypePointer Input %a3f16\n"
1947			"%f32_f16_function = OpTypeFunction %f32 %f16\n"
1948			"           %a3f32 = OpTypeArray %f32 %c_i32_3\n"
1949			"        %op_a3f32 = OpTypePointer Output %a3f32\n",
1950
1951			"f16",
1952			"f32",
1953			4,
1954			1,
1955		},
1956		{ // Vector cases
1957			"vector",
1958
1959			"%interface_op_func = OpFunction %v2f32 None %v2f32_v2f16_function\n"
1960			"        %io_param1 = OpFunctionParameter %v2f16\n"
1961			"            %entry = OpLabel\n"
1962			"			   %ret = OpFConvert %v2f32 %io_param1\n"
1963			"                     OpReturnValue %ret\n"
1964			"                     OpFunctionEnd\n",
1965
1966			"                 %f16 = OpTypeFloat 16\n"
1967			"		        %v2f16 = OpTypeVector %f16 2\n"
1968			"            %ip_v2f16 = OpTypePointer Input %v2f16\n"
1969			"             %a3v2f16 = OpTypeArray %v2f16 %c_i32_3\n"
1970			"          %ip_a3v2f16 = OpTypePointer Input %a3v2f16\n"
1971			"%v2f32_v2f16_function = OpTypeFunction %v2f32 %v2f16\n"
1972			"             %a3v2f32 = OpTypeArray %v2f32 %c_i32_3\n"
1973			"          %op_a3v2f32 = OpTypePointer Output %a3v2f32\n",
1974
1975			"v2f16",
1976			"v2f32",
1977			2 * 4,
1978			2,
1979		}
1980	};
1981
1982	VulkanFeatures	requiredFeatures;
1983	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT;
1984
1985	for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx)
1986	{
1987		fragments["interface_op_func"]	= cases[caseIdx].interfaceOpFunc;
1988		fragments["pre_main"]			= cases[caseIdx].preMain;
1989
1990		fragments["input_type"]			= cases[caseIdx].inputType;
1991		fragments["output_type"]		= cases[caseIdx].outputType;
1992
1993		GraphicsInterfaces	interfaces;
1994		const deUint32		numPerCase	= cases[caseIdx].numPerCase;
1995		vector<deFloat16>	subInputs	(numPerCase);
1996		vector<float>		subOutputs	(numPerCase);
1997
1998		for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx)
1999		{
2000			string			testName	= string(cases[caseIdx].name) + numberToString(caseNdx);
2001
2002			for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx)
2003			{
2004				subInputs[numNdx]	= float16Data[caseNdx * numPerCase + numNdx];
2005				subOutputs[numNdx]	= float32Data[caseNdx * numPerCase + numNdx];
2006			}
2007			interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT16), BufferSp(new Float16Buffer(subInputs))),
2008									  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT32), BufferSp(new Float32Buffer(subOutputs))));
2009			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures);
2010		}
2011	}
2012}
2013
2014void addGraphics16BitStorageInputOutputInt32To16Group (tcu::TestCaseGroup* testGroup)
2015{
2016	de::Random							rnd					(deStringHash(testGroup->getName()));
2017	RGBA								defaultColors[4];
2018	vector<string>						extensions;
2019	map<string, string>					fragments			= passthruFragments();
2020	const deUint32						numDataPoints		= 64;
2021	// inputs and outputs are declared to be vectors of signed integers.
2022	// However, depending on the test, they may be interpreted as unsiged
2023	// integers. That won't be a problem as long as we passed the bits
2024	// in faithfully to the pipeline.
2025	vector<deInt32>						inputs				= getInt32s(rnd, numDataPoints);
2026	vector<deInt16>						outputs;
2027
2028	outputs.reserve(inputs.size());
2029	for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
2030		outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx]));
2031
2032	extensions.push_back("VK_KHR_16bit_storage");
2033
2034	fragments["capability"]				= "OpCapability StorageInputOutput16\n";
2035	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"\n";
2036
2037	getDefaultColors(defaultColors);
2038
2039	const StringTemplate	scalarInterfaceOpFunc(
2040			"%interface_op_func = OpFunction %${type16} None %${type16}_${type32}_function\n"
2041			"        %io_param1 = OpFunctionParameter %${type32}\n"
2042			"            %entry = OpLabel\n"
2043			"			   %ret = ${convert} %${type16} %io_param1\n"
2044			"                     OpReturnValue %ret\n"
2045			"                     OpFunctionEnd\n");
2046
2047	const StringTemplate	scalarPreMain(
2048			"             %${type16} = OpTypeInt 16 ${signed}\n"
2049			"          %op_${type16} = OpTypePointer Output %${type16}\n"
2050			"           %a3${type16} = OpTypeArray %${type16} %c_i32_3\n"
2051			"        %op_a3${type16} = OpTypePointer Output %a3${type16}\n"
2052			"%${type16}_${type32}_function = OpTypeFunction %${type16} %${type32}\n"
2053			"           %a3${type32} = OpTypeArray %${type32} %c_i32_3\n"
2054			"        %ip_a3${type32} = OpTypePointer Input %a3${type32}\n");
2055
2056	const StringTemplate	vecInterfaceOpFunc(
2057			"%interface_op_func = OpFunction %${type16} None %${type16}_${type32}_function\n"
2058			"        %io_param1 = OpFunctionParameter %${type32}\n"
2059			"            %entry = OpLabel\n"
2060			"			   %ret = ${convert} %${type16} %io_param1\n"
2061			"                     OpReturnValue %ret\n"
2062			"                     OpFunctionEnd\n");
2063
2064	const StringTemplate	vecPreMain(
2065			"	                %i16 = OpTypeInt 16 1\n"
2066			"	                %u16 = OpTypeInt 16 0\n"
2067			"                 %v4i16 = OpTypeVector %i16 4\n"
2068			"                 %v4u16 = OpTypeVector %u16 4\n"
2069			"          %op_${type16} = OpTypePointer Output %${type16}\n"
2070			"           %a3${type16} = OpTypeArray %${type16} %c_i32_3\n"
2071			"        %op_a3${type16} = OpTypePointer Output %a3${type16}\n"
2072			"%${type16}_${type32}_function = OpTypeFunction %${type16} %${type32}\n"
2073			"           %a3${type32} = OpTypeArray %${type32} %c_i32_3\n"
2074			"        %ip_a3${type32} = OpTypePointer Input %a3${type32}\n");
2075
2076	struct Case
2077	{
2078		const char*				name;
2079		const StringTemplate&	interfaceOpFunc;
2080		const StringTemplate&	preMain;
2081		const char*				type32;
2082		const char*				type16;
2083		const char*				sign;
2084		const char*				opcode;
2085		deUint32				numPerCase;
2086		deUint32				numElements;
2087	};
2088
2089	Case	cases[]		=
2090	{
2091		{"scalar_sint",	scalarInterfaceOpFunc,	scalarPreMain,	"i32",		"i16",		"1",	"OpSConvert",	4,		1},
2092		{"scalar_uint",	scalarInterfaceOpFunc,	scalarPreMain,	"u32",		"u16",		"0",	"OpUConvert",	4,		1},
2093		{"vector_sint",	vecInterfaceOpFunc,		vecPreMain,		"v4i32",	"v4i16",	"1",	"OpSConvert",	4 * 4,	4},
2094		{"vector_uint",	vecInterfaceOpFunc,		vecPreMain,		"v4u32",	"v4u16",	"0",	"OpUConvert",	4 * 4,	4},
2095	};
2096
2097	VulkanFeatures	requiredFeatures;
2098	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT;
2099
2100	for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx)
2101	{
2102		map<string, string>				specs;
2103
2104		specs["type32"]					= cases[caseIdx].type32;
2105		specs["type16"]					= cases[caseIdx].type16;
2106		specs["signed"]					= cases[caseIdx].sign;
2107		specs["convert"]				= cases[caseIdx].opcode;
2108
2109		fragments["pre_main"]			= cases[caseIdx].preMain.specialize(specs);
2110		fragments["interface_op_func"]	= cases[caseIdx].interfaceOpFunc.specialize(specs);
2111		fragments["input_type"]			= cases[caseIdx].type32;
2112		fragments["output_type"]		= cases[caseIdx].type16;
2113
2114		GraphicsInterfaces				interfaces;
2115		const deUint32					numPerCase	= cases[caseIdx].numPerCase;
2116		vector<deInt32>					subInputs	(numPerCase);
2117		vector<deInt16>					subOutputs	(numPerCase);
2118
2119		for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx)
2120		{
2121			string			testName	= string(cases[caseIdx].name) + numberToString(caseNdx);
2122
2123			for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx)
2124			{
2125				subInputs[numNdx]	= inputs[caseNdx * numPerCase + numNdx];
2126				subOutputs[numNdx]	= outputs[caseNdx * numPerCase + numNdx];
2127			}
2128			if (strcmp(cases[caseIdx].sign, "1") == 0)
2129			{
2130				interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT32), BufferSp(new Int32Buffer(subInputs))),
2131										  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT16), BufferSp(new Int16Buffer(subOutputs))));
2132			}
2133			else
2134			{
2135				interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT32), BufferSp(new Int32Buffer(subInputs))),
2136										  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT16), BufferSp(new Int16Buffer(subOutputs))));
2137			}
2138			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures);
2139		}
2140	}
2141}
2142
2143void addGraphics16BitStorageInputOutputInt16To32Group (tcu::TestCaseGroup* testGroup)
2144{
2145	de::Random							rnd					(deStringHash(testGroup->getName()));
2146	RGBA								defaultColors[4];
2147	vector<string>						extensions;
2148	map<string, string>					fragments			= passthruFragments();
2149	const deUint32						numDataPoints		= 64;
2150	// inputs and outputs are declared to be vectors of signed integers.
2151	// However, depending on the test, they may be interpreted as unsiged
2152	// integers. That won't be a problem as long as we passed the bits
2153	// in faithfully to the pipeline.
2154	vector<deInt16>						inputs				= getInt16s(rnd, numDataPoints);
2155	vector<deInt32>						sOutputs;
2156	vector<deInt32>						uOutputs;
2157	const deUint16						signBitMask			= 0x8000;
2158	const deUint32						signExtendMask		= 0xffff0000;
2159
2160	sOutputs.reserve(inputs.size());
2161	uOutputs.reserve(inputs.size());
2162
2163	for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
2164	{
2165		uOutputs.push_back(static_cast<deUint16>(inputs[numNdx]));
2166		if (inputs[numNdx] & signBitMask)
2167			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask));
2168		else
2169			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx]));
2170	}
2171
2172	extensions.push_back("VK_KHR_16bit_storage");
2173
2174	fragments["capability"]				= "OpCapability StorageInputOutput16\n";
2175	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"\n";
2176
2177	getDefaultColors(defaultColors);
2178
2179	const StringTemplate scalarIfOpFunc	(
2180			"%interface_op_func = OpFunction %${type32} None %${type32}_${type16}_function\n"
2181			"        %io_param1 = OpFunctionParameter %${type16}\n"
2182			"            %entry = OpLabel\n"
2183			"			   %ret = ${convert} %${type32} %io_param1\n"
2184			"                     OpReturnValue %ret\n"
2185			"                     OpFunctionEnd\n");
2186
2187	const StringTemplate scalarPreMain	(
2188			"             %${type16} = OpTypeInt 16 ${signed}\n"
2189			"          %ip_${type16} = OpTypePointer Input %${type16}\n"
2190			"           %a3${type16} = OpTypeArray %${type16} %c_i32_3\n"
2191			"        %ip_a3${type16} = OpTypePointer Input %a3${type16}\n"
2192			"%${type32}_${type16}_function = OpTypeFunction %${type32} %${type16}\n"
2193			"           %a3${type32} = OpTypeArray %${type32} %c_i32_3\n"
2194			"        %op_a3${type32} = OpTypePointer Output %a3${type32}\n");
2195
2196	const StringTemplate vecIfOpFunc	(
2197			"%interface_op_func = OpFunction %${type32} None %${type32}_${type16}_function\n"
2198			"        %io_param1 = OpFunctionParameter %${type16}\n"
2199			"            %entry = OpLabel\n"
2200			"			   %ret = ${convert} %${type32} %io_param1\n"
2201			"                     OpReturnValue %ret\n"
2202			"                     OpFunctionEnd\n");
2203
2204	const StringTemplate vecPreMain	(
2205			"	                %i16 = OpTypeInt 16 1\n"
2206			"	                %u16 = OpTypeInt 16 0\n"
2207			"                 %v4i16 = OpTypeVector %i16 4\n"
2208			"                 %v4u16 = OpTypeVector %u16 4\n"
2209			"          %ip_${type16} = OpTypePointer Input %${type16}\n"
2210			"           %a3${type16} = OpTypeArray %${type16} %c_i32_3\n"
2211			"        %ip_a3${type16} = OpTypePointer Input %a3${type16}\n"
2212			"%${type32}_${type16}_function = OpTypeFunction %${type32} %${type16}\n"
2213			"           %a3${type32} = OpTypeArray %${type32} %c_i32_3\n"
2214			"        %op_a3${type32} = OpTypePointer Output %a3${type32}\n");
2215
2216	struct Case
2217	{
2218		const char*				name;
2219		const StringTemplate&	interfaceOpFunc;
2220		const StringTemplate&	preMain;
2221		const char*				type32;
2222		const char*				type16;
2223		const char*				sign;
2224		const char*				opcode;
2225		deUint32				numPerCase;
2226		deUint32				numElements;
2227	};
2228
2229	Case	cases[]		=
2230	{
2231		{"scalar_sint",	scalarIfOpFunc,	scalarPreMain,	"i32",		"i16",		"1",	"OpSConvert",	4,		1},
2232		{"scalar_uint",	scalarIfOpFunc,	scalarPreMain,	"u32",		"u16",		"0",	"OpUConvert",	4,		1},
2233		{"vector_sint",	vecIfOpFunc,	vecPreMain,		"v4i32",	"v4i16",	"1",	"OpSConvert",	4 * 4,	4},
2234		{"vector_uint",	vecIfOpFunc,	vecPreMain,		"v4u32",	"v4u16",	"0",	"OpUConvert",	4 * 4,	4},
2235	};
2236
2237	VulkanFeatures	requiredFeatures;
2238	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT;
2239
2240	for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx)
2241	{
2242		map<string, string>				specs;
2243
2244		specs["type32"]					= cases[caseIdx].type32;
2245		specs["type16"]					= cases[caseIdx].type16;
2246		specs["signed"]					= cases[caseIdx].sign;
2247		specs["convert"]				= cases[caseIdx].opcode;
2248
2249		fragments["pre_main"]			= cases[caseIdx].preMain.specialize(specs);
2250		fragments["interface_op_func"]	= cases[caseIdx].interfaceOpFunc.specialize(specs);
2251		fragments["input_type"]			= cases[caseIdx].type16;
2252		fragments["output_type"]		= cases[caseIdx].type32;
2253
2254		GraphicsInterfaces				interfaces;
2255		const deUint32					numPerCase	= cases[caseIdx].numPerCase;
2256		vector<deInt16>					subInputs	(numPerCase);
2257		vector<deInt32>					subOutputs	(numPerCase);
2258
2259		for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx)
2260		{
2261			string			testName	= string(cases[caseIdx].name) + numberToString(caseNdx);
2262
2263			for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx)
2264			{
2265				subInputs[numNdx]	= inputs[caseNdx * numPerCase + numNdx];
2266				if (cases[caseIdx].sign[0] == '1')
2267					subOutputs[numNdx]	= sOutputs[caseNdx * numPerCase + numNdx];
2268				else
2269					subOutputs[numNdx]	= uOutputs[caseNdx * numPerCase + numNdx];
2270			}
2271			if (strcmp(cases[caseIdx].sign, "1") == 0)
2272			{
2273				interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT16), BufferSp(new Int16Buffer(subInputs))),
2274										  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT32), BufferSp(new Int32Buffer(subOutputs))));
2275			}
2276			else
2277			{
2278				interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT16), BufferSp(new Int16Buffer(subInputs))),
2279										  std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT32), BufferSp(new Int32Buffer(subOutputs))));
2280			}
2281			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures);
2282		}
2283	}
2284}
2285
2286void addGraphics16BitStoragePushConstantFloat16To32Group (tcu::TestCaseGroup* testGroup)
2287{
2288	de::Random							rnd					(deStringHash(testGroup->getName()));
2289	map<string, string>					fragments;
2290	RGBA								defaultColors[4];
2291	vector<string>						extensions;
2292	GraphicsResources					resources;
2293	PushConstants						pcs;
2294	const deUint32						numDataPoints		= 64;
2295	vector<deFloat16>					float16Data			(getFloat16s(rnd, numDataPoints));
2296	vector<float>						float32Data;
2297	VulkanFeatures						requiredFeatures;
2298
2299	float32Data.reserve(numDataPoints);
2300	for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx)
2301		float32Data.push_back(deFloat16To32(float16Data[numIdx]));
2302
2303	extensions.push_back("VK_KHR_16bit_storage");
2304	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT;
2305
2306	fragments["capability"]				= "OpCapability StoragePushConstant16\n";
2307	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"";
2308
2309	pcs.setPushConstant(BufferSp(new Float16Buffer(float16Data)));
2310	resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data))));
2311	resources.verifyIO = check32BitFloats;
2312
2313	getDefaultColors(defaultColors);
2314
2315	const StringTemplate	testFun		(
2316		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2317		"    %param = OpFunctionParameter %v4f32\n"
2318
2319		"%entry = OpLabel\n"
2320		"    %i = OpVariable %fp_i32 Function\n"
2321		"         OpStore %i %c_i32_0\n"
2322		"         OpBranch %loop\n"
2323
2324		" %loop = OpLabel\n"
2325		"   %15 = OpLoad %i32 %i\n"
2326		"   %lt = OpSLessThan %bool %15 ${count}\n"
2327		"         OpLoopMerge %merge %inc None\n"
2328		"         OpBranchConditional %lt %write %merge\n"
2329
2330		"%write = OpLabel\n"
2331		"   %30 = OpLoad %i32 %i\n"
2332		"  %src = OpAccessChain ${pp_type16} %pc16 %c_i32_0 %30 ${index0:opt}\n"
2333		"%val16 = OpLoad ${f_type16} %src\n"
2334		"%val32 = OpFConvert ${f_type32} %val16\n"
2335		"  %dst = OpAccessChain ${up_type32} %ssbo32 %c_i32_0 %30 ${index0:opt}\n"
2336		"         OpStore %dst %val32\n"
2337
2338		"${store:opt}\n"
2339
2340		"         OpBranch %inc\n"
2341
2342		"  %inc = OpLabel\n"
2343		"   %37 = OpLoad %i32 %i\n"
2344		"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
2345		"         OpStore %i %39\n"
2346		"         OpBranch %loop\n"
2347
2348		"%merge = OpLabel\n"
2349		"         OpReturnValue %param\n"
2350
2351		"OpFunctionEnd\n");
2352
2353	{  // Scalar cases
2354		fragments["pre_main"]				=
2355			"      %f16 = OpTypeFloat 16\n"
2356			" %c_i32_64 = OpConstant %i32 64\n"					// Should be the same as numDataPoints
2357			"   %a64f16 = OpTypeArray %f16 %c_i32_64\n"
2358			"   %a64f32 = OpTypeArray %f32 %c_i32_64\n"
2359			"   %pp_f16 = OpTypePointer PushConstant %f16\n"
2360			"   %up_f32 = OpTypePointer Uniform %f32\n"
2361			"   %SSBO32 = OpTypeStruct %a64f32\n"
2362			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2363			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2364			"     %PC16 = OpTypeStruct %a64f16\n"
2365			"  %pp_PC16 = OpTypePointer PushConstant %PC16\n"
2366			"     %pc16 = OpVariable %pp_PC16 PushConstant\n";
2367
2368		fragments["decoration"]				=
2369			"OpDecorate %a64f16 ArrayStride 2\n"
2370			"OpDecorate %a64f32 ArrayStride 4\n"
2371			"OpDecorate %SSBO32 BufferBlock\n"
2372			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2373			"OpDecorate %PC16 Block\n"
2374			"OpMemberDecorate %PC16 0 Offset 0\n"
2375			"OpDecorate %ssbo32 DescriptorSet 0\n"
2376			"OpDecorate %ssbo32 Binding 0\n";
2377
2378		map<string, string>		specs;
2379
2380		specs["count"]			= "%c_i32_64";
2381		specs["pp_type16"]		= "%pp_f16";
2382		specs["f_type16"]		= "%f16";
2383		specs["f_type32"]		= "%f32";
2384		specs["up_type32"]		= "%up_f32";
2385
2386		fragments["testfun"]	= testFun.specialize(specs);
2387
2388		createTestsForAllStages("scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2389	}
2390
2391	{  // Vector cases
2392		fragments["pre_main"]				=
2393			"      %f16 = OpTypeFloat 16\n"
2394			"    %v4f16 = OpTypeVector %f16 4\n"
2395			" %c_i32_16 = OpConstant %i32 16\n"
2396			" %a16v4f16 = OpTypeArray %v4f16 %c_i32_16\n"
2397			" %a16v4f32 = OpTypeArray %v4f32 %c_i32_16\n"
2398			" %pp_v4f16 = OpTypePointer PushConstant %v4f16\n"
2399			" %up_v4f32 = OpTypePointer Uniform %v4f32\n"
2400			"   %SSBO32 = OpTypeStruct %a16v4f32\n"
2401			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2402			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2403			"     %PC16 = OpTypeStruct %a16v4f16\n"
2404			"  %pp_PC16 = OpTypePointer PushConstant %PC16\n"
2405			"     %pc16 = OpVariable %pp_PC16 PushConstant\n";
2406
2407		fragments["decoration"]				=
2408			"OpDecorate %a16v4f16 ArrayStride 8\n"
2409			"OpDecorate %a16v4f32 ArrayStride 16\n"
2410			"OpDecorate %SSBO32 BufferBlock\n"
2411			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2412			"OpDecorate %PC16 Block\n"
2413			"OpMemberDecorate %PC16 0 Offset 0\n"
2414			"OpDecorate %ssbo32 DescriptorSet 0\n"
2415			"OpDecorate %ssbo32 Binding 0\n";
2416
2417		map<string, string>		specs;
2418
2419		specs["count"]			= "%c_i32_16";
2420		specs["pp_type16"]		= "%pp_v4f16";
2421		specs["f_type16"]		= "%v4f16";
2422		specs["f_type32"]		= "%v4f32";
2423		specs["up_type32"]		= "%up_v4f32";
2424
2425		fragments["testfun"]	= testFun.specialize(specs);
2426
2427		createTestsForAllStages("vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2428	}
2429
2430	{  // Matrix cases
2431		fragments["pre_main"]				=
2432			"  %c_i32_8 = OpConstant %i32 8\n"
2433			"      %f16 = OpTypeFloat 16\n"
2434			"    %v4f16 = OpTypeVector %f16 4\n"
2435			"  %m2v4f16 = OpTypeMatrix %v4f16 2\n"
2436			"  %m2v4f32 = OpTypeMatrix %v4f32 2\n"
2437			"%a8m2v4f16 = OpTypeArray %m2v4f16 %c_i32_8\n"
2438			"%a8m2v4f32 = OpTypeArray %m2v4f32 %c_i32_8\n"
2439			" %pp_v4f16 = OpTypePointer PushConstant %v4f16\n"
2440			" %up_v4f32 = OpTypePointer Uniform %v4f32\n"
2441			"   %SSBO32 = OpTypeStruct %a8m2v4f32\n"
2442			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2443			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2444			"     %PC16 = OpTypeStruct %a8m2v4f16\n"
2445			"  %pp_PC16 = OpTypePointer PushConstant %PC16\n"
2446			"     %pc16 = OpVariable %pp_PC16 PushConstant\n";
2447
2448		fragments["decoration"]				=
2449			"OpDecorate %a8m2v4f16 ArrayStride 16\n"
2450			"OpDecorate %a8m2v4f32 ArrayStride 32\n"
2451			"OpDecorate %SSBO32 BufferBlock\n"
2452			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2453			"OpMemberDecorate %SSBO32 0 ColMajor\n"
2454			"OpMemberDecorate %SSBO32 0 MatrixStride 16\n"
2455			"OpDecorate %PC16 Block\n"
2456			"OpMemberDecorate %PC16 0 Offset 0\n"
2457			"OpMemberDecorate %PC16 0 ColMajor\n"
2458			"OpMemberDecorate %PC16 0 MatrixStride 8\n"
2459			"OpDecorate %ssbo32 DescriptorSet 0\n"
2460			"OpDecorate %ssbo32 Binding 0\n";
2461
2462		map<string, string>		specs;
2463
2464		specs["count"]			= "%c_i32_8";
2465		specs["pp_type16"]		= "%pp_v4f16";
2466		specs["up_type32"]		= "%up_v4f32";
2467		specs["f_type16"]		= "%v4f16";
2468		specs["f_type32"]		= "%v4f32";
2469		specs["index0"]			= "%c_i32_0";
2470		specs["store"]			=
2471			"  %src_1 = OpAccessChain %pp_v4f16 %pc16 %c_i32_0 %30 %c_i32_1\n"
2472			"%val16_1 = OpLoad %v4f16 %src_1\n"
2473			"%val32_1 = OpFConvert %v4f32 %val16_1\n"
2474			"  %dst_1 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_1\n"
2475			"           OpStore %dst_1 %val32_1\n";
2476
2477		fragments["testfun"]	= testFun.specialize(specs);
2478
2479		createTestsForAllStages("matrix", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2480	}
2481}
2482
2483void addGraphics16BitStoragePushConstantInt16To32Group (tcu::TestCaseGroup* testGroup)
2484{
2485	de::Random							rnd					(deStringHash(testGroup->getName()));
2486	map<string, string>					fragments;
2487	RGBA								defaultColors[4];
2488	const deUint32						numDataPoints		= 64;
2489	vector<deInt16>						inputs				= getInt16s(rnd, numDataPoints);
2490	vector<deInt32>						sOutputs;
2491	vector<deInt32>						uOutputs;
2492	PushConstants						pcs;
2493	GraphicsResources					resources;
2494	vector<string>						extensions;
2495	const deUint16						signBitMask			= 0x8000;
2496	const deUint32						signExtendMask		= 0xffff0000;
2497	VulkanFeatures						requiredFeatures;
2498
2499	sOutputs.reserve(inputs.size());
2500	uOutputs.reserve(inputs.size());
2501
2502	for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
2503	{
2504		uOutputs.push_back(static_cast<deUint16>(inputs[numNdx]));
2505		if (inputs[numNdx] & signBitMask)
2506			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask));
2507		else
2508			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx]));
2509	}
2510
2511	extensions.push_back("VK_KHR_16bit_storage");
2512	requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT;
2513
2514	fragments["capability"]				= "OpCapability StoragePushConstant16\n";
2515	fragments["extension"]				= "OpExtension \"SPV_KHR_16bit_storage\"";
2516
2517	pcs.setPushConstant(BufferSp(new Int16Buffer(inputs)));
2518
2519	getDefaultColors(defaultColors);
2520
2521	const StringTemplate	testFun		(
2522		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2523		"    %param = OpFunctionParameter %v4f32\n"
2524
2525		"%entry = OpLabel\n"
2526		"    %i = OpVariable %fp_i32 Function\n"
2527		"         OpStore %i %c_i32_0\n"
2528		"         OpBranch %loop\n"
2529
2530		" %loop = OpLabel\n"
2531		"   %15 = OpLoad %i32 %i\n"
2532		"   %lt = OpSLessThan %bool %15 %c_i32_${count}\n"
2533		"         OpLoopMerge %merge %inc None\n"
2534		"         OpBranchConditional %lt %write %merge\n"
2535
2536		"%write = OpLabel\n"
2537		"   %30 = OpLoad %i32 %i\n"
2538		"  %src = OpAccessChain %pp_${type16} %pc16 %c_i32_0 %30\n"
2539		"%val16 = OpLoad %${type16} %src\n"
2540		"%val32 = ${convert} %${type32} %val16\n"
2541		"  %dst = OpAccessChain %up_${type32} %ssbo32 %c_i32_0 %30\n"
2542		"         OpStore %dst %val32\n"
2543		"         OpBranch %inc\n"
2544
2545		"  %inc = OpLabel\n"
2546		"   %37 = OpLoad %i32 %i\n"
2547		"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
2548		"         OpStore %i %39\n"
2549		"         OpBranch %loop\n"
2550
2551		"%merge = OpLabel\n"
2552		"         OpReturnValue %param\n"
2553
2554		"OpFunctionEnd\n");
2555
2556	{  // Scalar cases
2557		const StringTemplate	preMain		(
2558			"         %${type16} = OpTypeInt 16 ${signed}\n"
2559			"    %c_i32_${count} = OpConstant %i32 ${count}\n"					// Should be the same as numDataPoints
2560			"%a${count}${type16} = OpTypeArray %${type16} %c_i32_${count}\n"
2561			"%a${count}${type32} = OpTypeArray %${type32} %c_i32_${count}\n"
2562			"      %pp_${type16} = OpTypePointer PushConstant %${type16}\n"
2563			"      %up_${type32} = OpTypePointer Uniform      %${type32}\n"
2564			"            %SSBO32 = OpTypeStruct %a${count}${type32}\n"
2565			"         %up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2566			"            %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2567			"              %PC16 = OpTypeStruct %a${count}${type16}\n"
2568			"           %pp_PC16 = OpTypePointer PushConstant %PC16\n"
2569			"              %pc16 = OpVariable %pp_PC16 PushConstant\n");
2570
2571		const StringTemplate	decoration	(
2572			"OpDecorate %a${count}${type16} ArrayStride 2\n"
2573			"OpDecorate %a${count}${type32} ArrayStride 4\n"
2574			"OpDecorate %SSBO32 BufferBlock\n"
2575			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2576			"OpDecorate %PC16 Block\n"
2577			"OpMemberDecorate %PC16 0 Offset 0\n"
2578			"OpDecorate %ssbo32 DescriptorSet 0\n"
2579			"OpDecorate %ssbo32 Binding 0\n");
2580
2581		{  // signed int
2582			map<string, string>		specs;
2583
2584			specs["type16"]			= "i16";
2585			specs["type32"]			= "i32";
2586			specs["signed"]			= "1";
2587			specs["count"]			= "64";
2588			specs["convert"]		= "OpSConvert";
2589
2590			fragments["testfun"]	= testFun.specialize(specs);
2591			fragments["pre_main"]	= preMain.specialize(specs);
2592			fragments["decoration"]	= decoration.specialize(specs);
2593
2594			resources.outputs.clear();
2595			resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs))));
2596			createTestsForAllStages("sint_scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2597		}
2598		{  // signed int
2599			map<string, string>		specs;
2600
2601			specs["type16"]			= "u16";
2602			specs["type32"]			= "u32";
2603			specs["signed"]			= "0";
2604			specs["count"]			= "64";
2605			specs["convert"]		= "OpUConvert";
2606
2607			fragments["testfun"]	= testFun.specialize(specs);
2608			fragments["pre_main"]	= preMain.specialize(specs);
2609			fragments["decoration"]	= decoration.specialize(specs);
2610
2611			resources.outputs.clear();
2612			resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs))));
2613			createTestsForAllStages("uint_scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2614		}
2615	}
2616
2617	{  // Vector cases
2618		const StringTemplate	preMain		(
2619			"    %${base_type16} = OpTypeInt 16 ${signed}\n"
2620			"         %${type16} = OpTypeVector %${base_type16} 2\n"
2621			"    %c_i32_${count} = OpConstant %i32 ${count}\n"
2622			"%a${count}${type16} = OpTypeArray %${type16} %c_i32_${count}\n"
2623			"%a${count}${type32} = OpTypeArray %${type32} %c_i32_${count}\n"
2624			"      %pp_${type16} = OpTypePointer PushConstant %${type16}\n"
2625			"      %up_${type32} = OpTypePointer Uniform      %${type32}\n"
2626			"            %SSBO32 = OpTypeStruct %a${count}${type32}\n"
2627			"         %up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2628			"            %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2629			"              %PC16 = OpTypeStruct %a${count}${type16}\n"
2630			"           %pp_PC16 = OpTypePointer PushConstant %PC16\n"
2631			"              %pc16 = OpVariable %pp_PC16 PushConstant\n");
2632
2633		const StringTemplate	decoration	(
2634			"OpDecorate %a${count}${type16} ArrayStride 4\n"
2635			"OpDecorate %a${count}${type32} ArrayStride 8\n"
2636			"OpDecorate %SSBO32 BufferBlock\n"
2637			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2638			"OpDecorate %PC16 Block\n"
2639			"OpMemberDecorate %PC16 0 Offset 0\n"
2640			"OpDecorate %ssbo32 DescriptorSet 0\n"
2641			"OpDecorate %ssbo32 Binding 0\n");
2642
2643		{  // signed int
2644			map<string, string>		specs;
2645
2646			specs["base_type16"]	= "i16";
2647			specs["type16"]			= "v2i16";
2648			specs["type32"]			= "v2i32";
2649			specs["signed"]			= "1";
2650			specs["count"]			= "32";				// 64 / 2
2651			specs["convert"]		= "OpSConvert";
2652
2653			fragments["testfun"]	= testFun.specialize(specs);
2654			fragments["pre_main"]	= preMain.specialize(specs);
2655			fragments["decoration"]	= decoration.specialize(specs);
2656
2657			resources.outputs.clear();
2658			resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs))));
2659			createTestsForAllStages("sint_vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2660		}
2661		{  // signed int
2662			map<string, string>		specs;
2663
2664			specs["base_type16"]	= "u16";
2665			specs["type16"]			= "v2u16";
2666			specs["type32"]			= "v2u32";
2667			specs["signed"]			= "0";
2668			specs["count"]			= "32";
2669			specs["convert"]		= "OpUConvert";
2670
2671			fragments["testfun"]	= testFun.specialize(specs);
2672			fragments["pre_main"]	= preMain.specialize(specs);
2673			fragments["decoration"]	= decoration.specialize(specs);
2674
2675			resources.outputs.clear();
2676			resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs))));
2677			createTestsForAllStages("uint_vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures);
2678		}
2679	}
2680}
2681
2682void addGraphics16BitStorageUniformInt16To32Group (tcu::TestCaseGroup* testGroup)
2683{
2684	de::Random							rnd					(deStringHash(testGroup->getName()));
2685	map<string, string>					fragments;
2686	const deUint32						numDataPoints		= 256;
2687	RGBA								defaultColors[4];
2688	vector<deInt16>						inputs				= getInt16s(rnd, numDataPoints);
2689	vector<deInt32>						sOutputs;
2690	vector<deInt32>						uOutputs;
2691	GraphicsResources					resources;
2692	vector<string>						extensions;
2693	const deUint16						signBitMask			= 0x8000;
2694	const deUint32						signExtendMask		= 0xffff0000;
2695	const StringTemplate				capabilities		("OpCapability ${cap}\n");
2696
2697	sOutputs.reserve(inputs.size());
2698	uOutputs.reserve(inputs.size());
2699
2700	for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx)
2701	{
2702		uOutputs.push_back(static_cast<deUint16>(inputs[numNdx]));
2703		if (inputs[numNdx] & signBitMask)
2704			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask));
2705		else
2706			sOutputs.push_back(static_cast<deInt32>(inputs[numNdx]));
2707	}
2708
2709	resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int16Buffer(inputs))));
2710
2711	extensions.push_back("VK_KHR_16bit_storage");
2712	fragments["extension"]	= "OpExtension \"SPV_KHR_16bit_storage\"";
2713
2714	getDefaultColors(defaultColors);
2715
2716	struct IntegerFacts
2717	{
2718		const char*	name;
2719		const char*	type32;
2720		const char*	type16;
2721		const char* opcode;
2722		bool		isSigned;
2723	};
2724
2725	const IntegerFacts	intFacts[]	=
2726	{
2727		{"sint",	"%i32",		"%i16",		"OpSConvert",	true},
2728		{"uint",	"%u32",		"%u16",		"OpUConvert",	false},
2729	};
2730
2731	const StringTemplate scalarPreMain		(
2732			"${itype16} = OpTypeInt 16 ${signed}\n"
2733			" %c_i32_256 = OpConstant %i32 256\n"
2734			"   %up_i32 = OpTypePointer Uniform ${itype32}\n"
2735			"   %up_i16 = OpTypePointer Uniform ${itype16}\n"
2736			"   %ra_i32 = OpTypeArray ${itype32} %c_i32_256\n"
2737			"   %ra_i16 = OpTypeArray ${itype16} %c_i32_256\n"
2738			"   %SSBO32 = OpTypeStruct %ra_i32\n"
2739			"   %SSBO16 = OpTypeStruct %ra_i16\n"
2740			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2741			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
2742			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2743			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n");
2744
2745	const StringTemplate scalarDecoration		(
2746			"OpDecorate %ra_i32 ArrayStride 4\n"
2747			"OpDecorate %ra_i16 ArrayStride 2\n"
2748			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2749			"OpMemberDecorate %SSBO16 0 Offset 0\n"
2750			"OpDecorate %SSBO32 BufferBlock\n"
2751			"OpDecorate %SSBO16 ${indecor}\n"
2752			"OpDecorate %ssbo32 DescriptorSet 0\n"
2753			"OpDecorate %ssbo16 DescriptorSet 0\n"
2754			"OpDecorate %ssbo32 Binding 1\n"
2755			"OpDecorate %ssbo16 Binding 0\n");
2756
2757	const StringTemplate scalarTestFunc	(
2758			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2759			"    %param = OpFunctionParameter %v4f32\n"
2760
2761			"%entry = OpLabel\n"
2762			"    %i = OpVariable %fp_i32 Function\n"
2763			"         OpStore %i %c_i32_0\n"
2764			"         OpBranch %loop\n"
2765
2766			" %loop = OpLabel\n"
2767			"   %15 = OpLoad %i32 %i\n"
2768			"   %lt = OpSLessThan %bool %15 %c_i32_256\n"
2769			"         OpLoopMerge %merge %inc None\n"
2770			"         OpBranchConditional %lt %write %merge\n"
2771
2772			"%write = OpLabel\n"
2773			"   %30 = OpLoad %i32 %i\n"
2774			"  %src = OpAccessChain %up_i16 %ssbo16 %c_i32_0 %30\n"
2775			"%val16 = OpLoad ${itype16} %src\n"
2776			"%val32 = ${convert} ${itype32} %val16\n"
2777			"  %dst = OpAccessChain %up_i32 %ssbo32 %c_i32_0 %30\n"
2778			"         OpStore %dst %val32\n"
2779			"         OpBranch %inc\n"
2780
2781			"  %inc = OpLabel\n"
2782			"   %37 = OpLoad %i32 %i\n"
2783			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
2784			"         OpStore %i %39\n"
2785			"         OpBranch %loop\n"
2786			"%merge = OpLabel\n"
2787			"         OpReturnValue %param\n"
2788
2789			"OpFunctionEnd\n");
2790
2791	const StringTemplate vecPreMain		(
2792			"${itype16} = OpTypeInt 16 ${signed}\n"
2793			"%c_i32_128 = OpConstant %i32 128\n"
2794			"%v2itype16 = OpTypeVector ${itype16} 2\n"
2795			"%v2itype32 = OpTypeVector ${itype32} 2\n"
2796			" %up_v2i32 = OpTypePointer Uniform %v2itype32\n"
2797			" %up_v2i16 = OpTypePointer Uniform %v2itype16\n"
2798			" %ra_v2i32 = OpTypeArray %v2itype32 %c_i32_128\n"
2799			" %ra_v2i16 = OpTypeArray %v2itype16 %c_i32_128\n"
2800			"   %SSBO32 = OpTypeStruct %ra_v2i32\n"
2801			"   %SSBO16 = OpTypeStruct %ra_v2i16\n"
2802			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2803			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
2804			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2805			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n");
2806
2807	const StringTemplate vecDecoration		(
2808			"OpDecorate %ra_v2i32 ArrayStride 8\n"
2809			"OpDecorate %ra_v2i16 ArrayStride 4\n"
2810			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2811			"OpMemberDecorate %SSBO16 0 Offset 0\n"
2812			"OpDecorate %SSBO32 BufferBlock\n"
2813			"OpDecorate %SSBO16 ${indecor}\n"
2814			"OpDecorate %ssbo32 DescriptorSet 0\n"
2815			"OpDecorate %ssbo16 DescriptorSet 0\n"
2816			"OpDecorate %ssbo32 Binding 1\n"
2817			"OpDecorate %ssbo16 Binding 0\n");
2818
2819	const StringTemplate vecTestFunc	(
2820			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2821			"    %param = OpFunctionParameter %v4f32\n"
2822
2823			"%entry = OpLabel\n"
2824			"    %i = OpVariable %fp_i32 Function\n"
2825			"         OpStore %i %c_i32_0\n"
2826			"         OpBranch %loop\n"
2827
2828			" %loop = OpLabel\n"
2829			"   %15 = OpLoad %i32 %i\n"
2830			"   %lt = OpSLessThan %bool %15 %c_i32_128\n"
2831			"         OpLoopMerge %merge %inc None\n"
2832			"         OpBranchConditional %lt %write %merge\n"
2833
2834			"%write = OpLabel\n"
2835			"   %30 = OpLoad %i32 %i\n"
2836			"  %src = OpAccessChain %up_v2i16 %ssbo16 %c_i32_0 %30\n"
2837			"%val16 = OpLoad %v2itype16 %src\n"
2838			"%val32 = ${convert} %v2itype32 %val16\n"
2839			"  %dst = OpAccessChain %up_v2i32 %ssbo32 %c_i32_0 %30\n"
2840			"         OpStore %dst %val32\n"
2841			"         OpBranch %inc\n"
2842
2843			"  %inc = OpLabel\n"
2844			"   %37 = OpLoad %i32 %i\n"
2845			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
2846			"         OpStore %i %39\n"
2847			"         OpBranch %loop\n"
2848			"%merge = OpLabel\n"
2849			"         OpReturnValue %param\n"
2850
2851			"OpFunctionEnd\n");
2852
2853	struct Category
2854	{
2855		const char*				name;
2856		const StringTemplate&	preMain;
2857		const StringTemplate&	decoration;
2858		const StringTemplate&	testFunction;
2859	};
2860
2861	const Category		categories[]	=
2862	{
2863		{"scalar", scalarPreMain, scalarDecoration, scalarTestFunc},
2864		{"vector", vecPreMain, vecDecoration, vecTestFunc},
2865	};
2866
2867	for (deUint32 catIdx = 0; catIdx < DE_LENGTH_OF_ARRAY(categories); ++catIdx)
2868		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
2869			for (deUint32 factIdx = 0; factIdx < DE_LENGTH_OF_ARRAY(intFacts); ++factIdx)
2870			{
2871				map<string, string>	specs;
2872				string				name		= string(CAPABILITIES[capIdx].name) + "_" + categories[catIdx].name + "_" + intFacts[factIdx].name;
2873
2874				specs["cap"]					= CAPABILITIES[capIdx].cap;
2875				specs["indecor"]				= CAPABILITIES[capIdx].decor;
2876				specs["itype32"]				= intFacts[factIdx].type32;
2877				specs["itype16"]				= intFacts[factIdx].type16;
2878				if (intFacts[factIdx].isSigned)
2879					specs["signed"]				= "1";
2880				else
2881					specs["signed"]				= "0";
2882				specs["convert"]				= intFacts[factIdx].opcode;
2883
2884				fragments["pre_main"]			= categories[catIdx].preMain.specialize(specs);
2885				fragments["testfun"]			= categories[catIdx].testFunction.specialize(specs);
2886				fragments["capability"]			= capabilities.specialize(specs);
2887				fragments["decoration"]			= categories[catIdx].decoration.specialize(specs);
2888
2889				resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
2890				resources.outputs.clear();
2891				if (intFacts[factIdx].isSigned)
2892					resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs))));
2893				else
2894					resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs))));
2895
2896				createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
2897			}
2898}
2899
2900void addGraphics16BitStorageUniformFloat16To32Group (tcu::TestCaseGroup* testGroup)
2901{
2902	de::Random							rnd					(deStringHash(testGroup->getName()));
2903	map<string, string>					fragments;
2904	GraphicsResources					resources;
2905	vector<string>						extensions;
2906	const deUint32						numDataPoints		= 256;
2907	RGBA								defaultColors[4];
2908	const StringTemplate				capabilities		("OpCapability ${cap}\n");
2909	vector<deFloat16>					float16Data			= getFloat16s(rnd, numDataPoints);
2910	vector<float>						float32Data;
2911
2912	float32Data.reserve(numDataPoints);
2913	for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx)
2914		float32Data.push_back(deFloat16To32(float16Data[numIdx]));
2915
2916	resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float16Buffer(float16Data))));
2917	resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data))));
2918	resources.verifyIO = check32BitFloats;
2919
2920	extensions.push_back("VK_KHR_16bit_storage");
2921	fragments["extension"]	= "OpExtension \"SPV_KHR_16bit_storage\"";
2922
2923	getDefaultColors(defaultColors);
2924
2925	{ // scalar cases
2926		fragments["pre_main"]				=
2927			"      %f16 = OpTypeFloat 16\n"
2928			"%c_i32_256 = OpConstant %i32 256\n"
2929			"   %up_f32 = OpTypePointer Uniform %f32\n"
2930			"   %up_f16 = OpTypePointer Uniform %f16\n"
2931			"   %ra_f32 = OpTypeArray %f32 %c_i32_256\n"
2932			"   %ra_f16 = OpTypeArray %f16 %c_i32_256\n"
2933			"   %SSBO32 = OpTypeStruct %ra_f32\n"
2934			"   %SSBO16 = OpTypeStruct %ra_f16\n"
2935			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
2936			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
2937			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
2938			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
2939
2940		const StringTemplate decoration		(
2941			"OpDecorate %ra_f32 ArrayStride 4\n"
2942			"OpDecorate %ra_f16 ArrayStride 2\n"
2943			"OpMemberDecorate %SSBO32 0 Offset 0\n"
2944			"OpMemberDecorate %SSBO16 0 Offset 0\n"
2945			"OpDecorate %SSBO32 BufferBlock\n"
2946			"OpDecorate %SSBO16 ${indecor}\n"
2947			"OpDecorate %ssbo32 DescriptorSet 0\n"
2948			"OpDecorate %ssbo16 DescriptorSet 0\n"
2949			"OpDecorate %ssbo32 Binding 1\n"
2950			"OpDecorate %ssbo16 Binding 0\n");
2951
2952		// ssbo32[] <- convert ssbo16[] to 32bit float
2953		fragments["testfun"]				=
2954			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2955			"    %param = OpFunctionParameter %v4f32\n"
2956
2957			"%entry = OpLabel\n"
2958			"    %i = OpVariable %fp_i32 Function\n"
2959			"         OpStore %i %c_i32_0\n"
2960			"         OpBranch %loop\n"
2961
2962			" %loop = OpLabel\n"
2963			"   %15 = OpLoad %i32 %i\n"
2964			"   %lt = OpSLessThan %bool %15 %c_i32_256\n"
2965			"         OpLoopMerge %merge %inc None\n"
2966			"         OpBranchConditional %lt %write %merge\n"
2967
2968			"%write = OpLabel\n"
2969			"   %30 = OpLoad %i32 %i\n"
2970			"  %src = OpAccessChain %up_f16 %ssbo16 %c_i32_0 %30\n"
2971			"%val16 = OpLoad %f16 %src\n"
2972			"%val32 = OpFConvert %f32 %val16\n"
2973			"  %dst = OpAccessChain %up_f32 %ssbo32 %c_i32_0 %30\n"
2974			"         OpStore %dst %val32\n"
2975			"         OpBranch %inc\n"
2976
2977			"  %inc = OpLabel\n"
2978			"   %37 = OpLoad %i32 %i\n"
2979			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
2980			"         OpStore %i %39\n"
2981			"         OpBranch %loop\n"
2982
2983			"%merge = OpLabel\n"
2984			"         OpReturnValue %param\n"
2985
2986			"OpFunctionEnd\n";
2987
2988		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
2989		{
2990			map<string, string>	specs;
2991			string				testName	= string(CAPABILITIES[capIdx].name) + "_scalar_float";
2992
2993			specs["cap"]					= CAPABILITIES[capIdx].cap;
2994			specs["indecor"]				= CAPABILITIES[capIdx].decor;
2995
2996			fragments["capability"]			= capabilities.specialize(specs);
2997			fragments["decoration"]			= decoration.specialize(specs);
2998
2999			resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
3000
3001			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
3002		}
3003	}
3004
3005	{ // vector cases
3006		fragments["pre_main"]				=
3007			"      %f16 = OpTypeFloat 16\n"
3008			"%c_i32_128 = OpConstant %i32 128\n"
3009			"	 %v2f16 = OpTypeVector %f16 2\n"
3010			" %up_v2f32 = OpTypePointer Uniform %v2f32\n"
3011			" %up_v2f16 = OpTypePointer Uniform %v2f16\n"
3012			" %ra_v2f32 = OpTypeArray %v2f32 %c_i32_128\n"
3013			" %ra_v2f16 = OpTypeArray %v2f16 %c_i32_128\n"
3014			"   %SSBO32 = OpTypeStruct %ra_v2f32\n"
3015			"   %SSBO16 = OpTypeStruct %ra_v2f16\n"
3016			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
3017			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
3018			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
3019			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
3020
3021		const StringTemplate decoration		(
3022			"OpDecorate %ra_v2f32 ArrayStride 8\n"
3023			"OpDecorate %ra_v2f16 ArrayStride 4\n"
3024			"OpMemberDecorate %SSBO32 0 Offset 0\n"
3025			"OpMemberDecorate %SSBO16 0 Offset 0\n"
3026			"OpDecorate %SSBO32 BufferBlock\n"
3027			"OpDecorate %SSBO16 ${indecor}\n"
3028			"OpDecorate %ssbo32 DescriptorSet 0\n"
3029			"OpDecorate %ssbo16 DescriptorSet 0\n"
3030			"OpDecorate %ssbo32 Binding 1\n"
3031			"OpDecorate %ssbo16 Binding 0\n");
3032
3033		// ssbo32[] <- convert ssbo16[] to 32bit float
3034		fragments["testfun"]				=
3035			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
3036			"    %param = OpFunctionParameter %v4f32\n"
3037
3038			"%entry = OpLabel\n"
3039			"    %i = OpVariable %fp_i32 Function\n"
3040			"         OpStore %i %c_i32_0\n"
3041			"         OpBranch %loop\n"
3042
3043			" %loop = OpLabel\n"
3044			"   %15 = OpLoad %i32 %i\n"
3045			"   %lt = OpSLessThan %bool %15 %c_i32_128\n"
3046			"         OpLoopMerge %merge %inc None\n"
3047			"         OpBranchConditional %lt %write %merge\n"
3048
3049			"%write = OpLabel\n"
3050			"   %30 = OpLoad %i32 %i\n"
3051			"  %src = OpAccessChain %up_v2f16 %ssbo16 %c_i32_0 %30\n"
3052			"%val16 = OpLoad %v2f16 %src\n"
3053			"%val32 = OpFConvert %v2f32 %val16\n"
3054			"  %dst = OpAccessChain %up_v2f32 %ssbo32 %c_i32_0 %30\n"
3055			"         OpStore %dst %val32\n"
3056			"         OpBranch %inc\n"
3057
3058			"  %inc = OpLabel\n"
3059			"   %37 = OpLoad %i32 %i\n"
3060			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
3061			"         OpStore %i %39\n"
3062			"         OpBranch %loop\n"
3063
3064			"%merge = OpLabel\n"
3065			"         OpReturnValue %param\n"
3066
3067			"OpFunctionEnd\n";
3068
3069		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
3070		{
3071			map<string, string>	specs;
3072			string				testName	= string(CAPABILITIES[capIdx].name) + "_vector_float";
3073
3074			specs["cap"]					= CAPABILITIES[capIdx].cap;
3075			specs["indecor"]				= CAPABILITIES[capIdx].decor;
3076
3077			fragments["capability"]			= capabilities.specialize(specs);
3078			fragments["decoration"]			= decoration.specialize(specs);
3079
3080			resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
3081
3082			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
3083		}
3084	}
3085
3086	{ // matrix cases
3087		fragments["pre_main"]				=
3088			" %c_i32_32 = OpConstant %i32 32\n"
3089			"      %f16 = OpTypeFloat 16\n"
3090			"    %v2f16 = OpTypeVector %f16 2\n"
3091			"  %m4x2f32 = OpTypeMatrix %v2f32 4\n"
3092			"  %m4x2f16 = OpTypeMatrix %v2f16 4\n"
3093			" %up_v2f32 = OpTypePointer Uniform %v2f32\n"
3094			" %up_v2f16 = OpTypePointer Uniform %v2f16\n"
3095			"%a8m4x2f32 = OpTypeArray %m4x2f32 %c_i32_32\n"
3096			"%a8m4x2f16 = OpTypeArray %m4x2f16 %c_i32_32\n"
3097			"   %SSBO32 = OpTypeStruct %a8m4x2f32\n"
3098			"   %SSBO16 = OpTypeStruct %a8m4x2f16\n"
3099			"%up_SSBO32 = OpTypePointer Uniform %SSBO32\n"
3100			"%up_SSBO16 = OpTypePointer Uniform %SSBO16\n"
3101			"   %ssbo32 = OpVariable %up_SSBO32 Uniform\n"
3102			"   %ssbo16 = OpVariable %up_SSBO16 Uniform\n";
3103
3104		const StringTemplate decoration		(
3105			"OpDecorate %a8m4x2f32 ArrayStride 32\n"
3106			"OpDecorate %a8m4x2f16 ArrayStride 16\n"
3107			"OpMemberDecorate %SSBO32 0 Offset 0\n"
3108			"OpMemberDecorate %SSBO32 0 ColMajor\n"
3109			"OpMemberDecorate %SSBO32 0 MatrixStride 8\n"
3110			"OpMemberDecorate %SSBO16 0 Offset 0\n"
3111			"OpMemberDecorate %SSBO16 0 ColMajor\n"
3112			"OpMemberDecorate %SSBO16 0 MatrixStride 4\n"
3113			"OpDecorate %SSBO32 BufferBlock\n"
3114			"OpDecorate %SSBO16 ${indecor}\n"
3115			"OpDecorate %ssbo32 DescriptorSet 0\n"
3116			"OpDecorate %ssbo16 DescriptorSet 0\n"
3117			"OpDecorate %ssbo32 Binding 1\n"
3118			"OpDecorate %ssbo16 Binding 0\n");
3119
3120		fragments["testfun"]				=
3121			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
3122			"    %param = OpFunctionParameter %v4f32\n"
3123
3124			"%entry = OpLabel\n"
3125			"    %i = OpVariable %fp_i32 Function\n"
3126			"         OpStore %i %c_i32_0\n"
3127			"         OpBranch %loop\n"
3128
3129			" %loop = OpLabel\n"
3130			"   %15 = OpLoad %i32 %i\n"
3131			"   %lt = OpSLessThan %bool %15 %c_i32_32\n"
3132			"         OpLoopMerge %merge %inc None\n"
3133			"         OpBranchConditional %lt %write %merge\n"
3134
3135			"  %write = OpLabel\n"
3136			"     %30 = OpLoad %i32 %i\n"
3137			"  %src_0 = OpAccessChain %up_v2f16 %ssbo16 %c_i32_0 %30 %c_i32_0\n"
3138			"  %src_1 = OpAccessChain %up_v2f16 %ssbo16 %c_i32_0 %30 %c_i32_1\n"
3139			"  %src_2 = OpAccessChain %up_v2f16 %ssbo16 %c_i32_0 %30 %c_i32_2\n"
3140			"  %src_3 = OpAccessChain %up_v2f16 %ssbo16 %c_i32_0 %30 %c_i32_3\n"
3141			"%val16_0 = OpLoad %v2f16 %src_0\n"
3142			"%val16_1 = OpLoad %v2f16 %src_1\n"
3143			"%val16_2 = OpLoad %v2f16 %src_2\n"
3144			"%val16_3 = OpLoad %v2f16 %src_3\n"
3145			"%val32_0 = OpFConvert %v2f32 %val16_0\n"
3146			"%val32_1 = OpFConvert %v2f32 %val16_1\n"
3147			"%val32_2 = OpFConvert %v2f32 %val16_2\n"
3148			"%val32_3 = OpFConvert %v2f32 %val16_3\n"
3149			"  %dst_0 = OpAccessChain %up_v2f32 %ssbo32 %c_i32_0 %30 %c_i32_0\n"
3150			"  %dst_1 = OpAccessChain %up_v2f32 %ssbo32 %c_i32_0 %30 %c_i32_1\n"
3151			"  %dst_2 = OpAccessChain %up_v2f32 %ssbo32 %c_i32_0 %30 %c_i32_2\n"
3152			"  %dst_3 = OpAccessChain %up_v2f32 %ssbo32 %c_i32_0 %30 %c_i32_3\n"
3153			"           OpStore %dst_0 %val32_0\n"
3154			"           OpStore %dst_1 %val32_1\n"
3155			"           OpStore %dst_2 %val32_2\n"
3156			"           OpStore %dst_3 %val32_3\n"
3157			"           OpBranch %inc\n"
3158
3159			"  %inc = OpLabel\n"
3160			"   %37 = OpLoad %i32 %i\n"
3161			"   %39 = OpIAdd %i32 %37 %c_i32_1\n"
3162			"         OpStore %i %39\n"
3163			"         OpBranch %loop\n"
3164
3165			"%merge = OpLabel\n"
3166			"         OpReturnValue %param\n"
3167
3168			"OpFunctionEnd\n";
3169
3170		for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
3171		{
3172			map<string, string>	specs;
3173			string				testName	= string(CAPABILITIES[capIdx].name) + "_matrix_float";
3174
3175			specs["cap"]					= CAPABILITIES[capIdx].cap;
3176			specs["indecor"]				= CAPABILITIES[capIdx].decor;
3177
3178			fragments["capability"]			= capabilities.specialize(specs);
3179			fragments["decoration"]			= decoration.specialize(specs);
3180
3181			resources.inputs.back().first	= CAPABILITIES[capIdx].dtype;
3182
3183			createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name));
3184		}
3185	}
3186}
3187
3188} // anonymous
3189
3190tcu::TestCaseGroup* create16BitStorageComputeGroup (tcu::TestContext& testCtx)
3191{
3192	de::MovePtr<tcu::TestCaseGroup> group		(new tcu::TestCaseGroup(testCtx, "16bit_storage", "Compute tests for VK_KHR_16bit_storage extension"));
3193	addTestGroup(group.get(), "uniform_32_to_16", "32bit floats/ints to 16bit tests under capability StorageUniform{|BufferBlock}", addCompute16bitStorageUniform32To16Group);
3194	addTestGroup(group.get(), "uniform_16_to_32", "16bit floats/ints to 32bit tests under capability StorageUniform{|BufferBlock}", addCompute16bitStorageUniform16To32Group);
3195	addTestGroup(group.get(), "push_constant_16_to_32", "16bit floats/ints to 32bit tests under capability StoragePushConstant16", addCompute16bitStoragePushConstant16To32Group);
3196
3197	return group.release();
3198}
3199
3200tcu::TestCaseGroup* create16BitStorageGraphicsGroup (tcu::TestContext& testCtx)
3201{
3202	de::MovePtr<tcu::TestCaseGroup> group		(new tcu::TestCaseGroup(testCtx, "16bit_storage", "Graphics tests for VK_KHR_16bit_storage extension"));
3203
3204	addTestGroup(group.get(), "uniform_float_32_to_16", "32-bit floats into 16-bit tests under capability StorageUniform{|BufferBlock}16", addGraphics16BitStorageUniformFloat32To16Group);
3205	addTestGroup(group.get(), "uniform_float_16_to_32", "16-bit floats into 32-bit testsunder capability StorageUniform{|BufferBlock}16", addGraphics16BitStorageUniformFloat16To32Group);
3206	addTestGroup(group.get(), "uniform_int_32_to_16", "32-bit int into 16-bit tests under capability StorageUniform{|BufferBlock}16", addGraphics16BitStorageUniformInt32To16Group);
3207	addTestGroup(group.get(), "uniform_int_16_to_32", "16-bit int into 32-bit tests under capability StorageUniform{|BufferBlock}16", addGraphics16BitStorageUniformInt16To32Group);
3208	addTestGroup(group.get(), "input_output_float_32_to_16", "32-bit floats into 16-bit tests under capability StorageInputOutput16", addGraphics16BitStorageInputOutputFloat32To16Group);
3209	addTestGroup(group.get(), "input_output_float_16_to_32", "16-bit floats into 32-bit tests under capability StorageInputOutput16", addGraphics16BitStorageInputOutputFloat16To32Group);
3210	addTestGroup(group.get(), "input_output_int_32_to_16", "32-bit int into 16-bit tests under capability StorageInputOutput16", addGraphics16BitStorageInputOutputInt32To16Group);
3211	addTestGroup(group.get(), "input_output_int_16_to_32", "16-bit int into 32-bit tests under capability StorageInputOutput16", addGraphics16BitStorageInputOutputInt16To32Group);
3212	addTestGroup(group.get(), "push_constant_float_16_to_32", "16-bit floats into 32-bit tests under capability StoragePushConstant16", addGraphics16BitStoragePushConstantFloat16To32Group);
3213	addTestGroup(group.get(), "push_constant_int_16_to_32", "16-bit int into 32-bit tests under capability StoragePushConstant16", addGraphics16BitStoragePushConstantInt16To32Group);
3214
3215	return group.release();
3216}
3217
3218} // SpirVAssembly
3219} // vkt
3220