1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Nintendo
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Pipeline specialization constants tests
24 *//*--------------------------------------------------------------------*/
25
26#include "vktPipelineSpecConstantTests.hpp"
27#include "vktTestCase.hpp"
28#include "vktPipelineSpecConstantUtil.hpp"
29#include "vktPipelineMakeUtil.hpp"
30
31#include "tcuTestLog.hpp"
32#include "tcuTexture.hpp"
33#include "tcuFormatUtil.hpp"
34#include "tcuFloat.hpp"
35
36#include "gluShaderUtil.hpp"
37
38#include "vkBuilderUtil.hpp"
39#include "vkPrograms.hpp"
40#include "vkRefUtil.hpp"
41#include "vkTypeUtil.hpp"
42#include "vkImageUtil.hpp"
43#include "vkBarrierUtil.hpp"
44#include "vkCmdUtil.hpp"
45#include "vkObjUtil.hpp"
46#include "vkBufferWithMemory.hpp"
47#include "vkImageWithMemory.hpp"
48#include "vkComputePipelineConstructionUtil.hpp"
49
50#include "deUniquePtr.hpp"
51#include "deStringUtil.hpp"
52
53#include <limits>
54
55namespace vkt
56{
57namespace pipeline
58{
59
60using namespace vk;
61
62namespace
63{
64
65static const char* const s_perVertexBlock =	"gl_PerVertex {\n"
66											"    vec4 gl_Position;\n"
67											"}";
68
69//! Raw memory storage for values used in test cases.
70//! We use it to simplify test case definitions where different types are expected in the result.
71class GenericValue
72{
73public:
74	GenericValue (void) { clear(); }
75
76	//! Copy up to 'size' bytes of 'data'.
77	GenericValue (const void* data, const deUint32 size)
78	{
79		DE_ASSERT(size <= sizeof(m_data));
80		clear();
81		deMemcpy(&m_data, data, size);
82	}
83
84private:
85	deUint64 m_data;
86
87	void clear (void) { m_data = 0; }
88};
89
90inline GenericValue makeValueBool32	 (const bool a)			{ return GenericValue(&a, sizeof(a)); }
91inline GenericValue makeValueInt8    (const deInt8 a)		{ return GenericValue(&a, sizeof(a)); }
92inline GenericValue makeValueUint8   (const deUint8 a)		{ return GenericValue(&a, sizeof(a)); }
93inline GenericValue makeValueInt16   (const deInt16 a)		{ return GenericValue(&a, sizeof(a)); }
94inline GenericValue makeValueUint16  (const deUint16 a)		{ return GenericValue(&a, sizeof(a)); }
95inline GenericValue makeValueInt32	 (const deInt32 a)		{ return GenericValue(&a, sizeof(a)); }
96inline GenericValue makeValueUint32	 (const deUint32 a)		{ return GenericValue(&a, sizeof(a)); }
97inline GenericValue makeValueInt64   (const deInt64 a)		{ return GenericValue(&a, sizeof(a)); }
98inline GenericValue makeValueUint64  (const deUint64 a)		{ return GenericValue(&a, sizeof(a)); }
99inline GenericValue makeValueFloat16 (const tcu::Float16 a)	{ return GenericValue(&a, sizeof(a)); }
100inline GenericValue makeValueFloat32 (const float a)		{ return GenericValue(&a, sizeof(a)); }
101inline GenericValue makeValueFloat64 (const double a)		{ return GenericValue(&a, sizeof(a)); }
102
103struct SpecConstant
104{
105	deUint32			specID;				//!< specialization constant ID
106	std::string			declarationCode;	//!< syntax to declare the constant, use ${ID} as an ID placeholder
107	deUint32			size;				//!< data size on the host, 0 = no specialized value
108	GenericValue		specValue;			//!< specialized value passed by the API
109	bool				forceUse;			//!< always include a VkSpecializationMapEntry for this spec constant
110
111	SpecConstant (const deUint32 specID_, const std::string declarationCode_)
112		: specID			(specID_)
113		, declarationCode	(declarationCode_)
114		, size				(0)
115		, specValue			()
116		, forceUse			(false)
117	{
118	}
119
120	SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_, bool forceUse_ = false)
121		: specID			(specID_)
122		, declarationCode	(declarationCode_)
123		, size				(size_)
124		, specValue			(specValue_)
125		, forceUse			(forceUse_)
126	{
127	}
128};
129
130//! Useful when referring to a value in a buffer (i.e. check expected values in SSBO).
131struct OffsetValue
132{
133	deUint32		size;		//!< data size in the buffer (up to sizeof(value))
134	deUint32		offset;		//!< offset into the buffer
135	GenericValue	value;		//!< value expected to be there
136
137	OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_)
138		: size		(size_)
139		, offset	(offset_)
140		, value		(value_)
141	{}
142};
143
144//! Get the integer value of 'size' bytes at 'memory' location.
145deUint64 memoryAsInteger (const void* memory, const deUint32 size)
146{
147	DE_ASSERT(size <= sizeof(deUint64));
148	deUint64 value = 0;
149	deMemcpy(&value, memory, size);
150	return value;
151}
152
153inline std::string memoryAsHexString (const void* memory, const deUint32 size)
154{
155	const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory);
156	return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size)));
157}
158
159void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size)
160{
161	const bool canDisplayValue = (size <= sizeof(deUint64));
162	log << tcu::TestLog::Message
163		<< "Comparison failed for value at offset " << de::toString(offset) << ": expected "
164		<< (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got "
165		<< (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size)
166		<< tcu::TestLog::EndMessage;
167}
168
169//! Check if expected values exist in the memory.
170bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues)
171{
172	bool ok = true;
173	log << tcu::TestLog::Section("compare", "Verify result values");
174
175	for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it)
176	{
177		const char* const valuePtr = static_cast<const char*>(memory) + it->offset;
178		if (deMemCmp(valuePtr, &it->value, it->size) != 0)
179		{
180			ok = false;
181			logValueMismatch(log, &it->value, valuePtr, it->offset, it->size);
182		}
183	}
184
185	if (ok)
186		log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage;
187
188	log << tcu::TestLog::EndSection;
189	return ok;
190}
191
192//! Bundles together common test case parameters.
193struct CaseDefinition
194{
195	std::string					name;				//!< Test case name
196	std::vector<SpecConstant>	specConstants;		//!< list of specialization constants to declare
197	VkDeviceSize				ssboSize;			//!< required ssbo size in bytes
198	std::string					ssboCode;			//!< ssbo member definitions
199	std::string					globalCode;			//!< generic shader code outside the main function (e.g. declarations)
200	std::string					mainCode;			//!< generic shader code to execute in main (e.g. assignments)
201	std::vector<OffsetValue>	expectedValues;		//!< list of values to check inside the ssbo buffer
202	FeatureFlags				requirements;		//!< features the implementation must support to allow this test to run
203	bool						packData;			//!< whether to tightly pack specialization constant data or not
204};
205
206//! Manages Vulkan structures to pass specialization data.
207class Specialization
208{
209public:
210											Specialization (const std::vector<SpecConstant>& specConstants, bool packData);
211
212	//! Can return NULL if nothing is specialized
213	const VkSpecializationInfo*				getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; }
214
215private:
216	std::vector<deUint8>					m_data;
217	std::vector<VkSpecializationMapEntry>	m_entries;
218	VkSpecializationInfo					m_specialization;
219};
220
221Specialization::Specialization (const std::vector<SpecConstant>& specConstants, bool packData)
222{
223	const auto kGenericValueSize = static_cast<deUint32>(sizeof(GenericValue));
224
225	// Reserve memory for the worst case in m_data.
226	m_data.resize(specConstants.size() * kGenericValueSize, std::numeric_limits<deUint8>::max());
227	m_entries.reserve(specConstants.size());
228
229	deUint32 offset = 0u;
230	for (const auto& sc : specConstants)
231	{
232		if (sc.size != 0u || sc.forceUse)
233		{
234			if (sc.size > 0u)
235				deMemcpy(&m_data[offset], &sc.specValue, sc.size);
236			m_entries.push_back(makeSpecializationMapEntry(sc.specID, offset, sc.size));
237			offset += (packData ? sc.size : kGenericValueSize);
238		}
239	}
240
241	if (m_entries.size() > 0)
242	{
243		m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size());
244		m_specialization.pMapEntries   = m_entries.data();
245		m_specialization.dataSize	   = static_cast<deUintptr>(offset);
246		m_specialization.pData		   = m_data.data();
247	}
248	else
249		deMemset(&m_specialization, 0, sizeof(m_specialization));
250}
251
252class SpecConstantTest : public TestCase
253{
254public:
255								SpecConstantTest	(tcu::TestContext&				testCtx,
256													 const PipelineConstructionType pipelineType,	//!< how pipeline is constructed
257													 const VkShaderStageFlagBits	stage,			//!< which shader stage is tested
258													 const CaseDefinition&			caseDef);
259
260	void						initPrograms		(SourceCollections&		programCollection) const;
261	TestInstance*				createInstance		(Context&				context) const;
262	virtual void				checkSupport		(Context&				context) const;
263
264private:
265	const PipelineConstructionType	m_pipelineConstructionType;
266	const VkShaderStageFlagBits		m_stage;
267	const CaseDefinition			m_caseDef;
268};
269
270SpecConstantTest::SpecConstantTest (tcu::TestContext&				testCtx,
271									const PipelineConstructionType	pipelineType,
272									const VkShaderStageFlagBits		stage,
273									const CaseDefinition&			caseDef)
274	: TestCase						(testCtx, caseDef.name)
275	, m_pipelineConstructionType	(pipelineType)
276	, m_stage						(stage)
277	, m_caseDef						(caseDef)
278{
279}
280
281//! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers.
282std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants)
283{
284	std::ostringstream code;
285	for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
286	{
287		std::string decl = it->declarationCode;
288		const std::string::size_type pos = decl.find("${ID}");
289		if (pos != std::string::npos)
290			decl.replace(pos, 5, de::toString(it->specID));
291		code << decl << "\n";
292	}
293	code << "\n";
294	return code.str();
295}
296
297std::string generateSSBOCode (const std::string& memberDeclarations)
298{
299	std::ostringstream code;
300	code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n"
301		 << memberDeclarations
302		 << "} sb_out;\n"
303		 << "\n";
304	return code.str();
305}
306
307void SpecConstantTest::initPrograms (SourceCollections& programCollection) const
308{
309	// Always add vertex and fragment to graphics stages
310	VkShaderStageFlags requiredStages = m_stage;
311
312	if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS)
313		requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
314
315	if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
316		requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
317
318	// Either graphics or compute must be defined, but not both
319	DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0));
320
321	// Extensions needed for some tests.
322	std::ostringstream extStream;
323	if (m_caseDef.requirements & FEATURE_SHADER_INT_64)
324		extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
325	if (m_caseDef.requirements & FEATURE_SHADER_INT_16)
326		extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require\n";
327	if (m_caseDef.requirements & FEATURE_SHADER_INT_8)
328		extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require\n";
329	if (m_caseDef.requirements & FEATURE_SHADER_FLOAT_16)
330		extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require\n";
331	const std::string extensions = extStream.str();
332
333	// This makes glslang avoid the UniformAndStorage* capabilities.
334	const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
335
336	if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT)
337	{
338		const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT);
339		std::ostringstream src;
340		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
341			<< extensions
342			<< "layout(location = 0) in highp vec4 position;\n"
343			<< "\n"
344			<< "out " << s_perVertexBlock << ";\n"
345			<< "\n"
346			<< (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
347			<< (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
348			<< (useSpecConst ? m_caseDef.globalCode + "\n" : "")
349			<< "void main (void)\n"
350			<< "{\n"
351			<< (useSpecConst ? m_caseDef.mainCode + "\n" : "")
352			<< "    gl_Position = position;\n"
353			<< "}\n";
354
355		programCollection.glslSources.add("vert") << glu::VertexSource(src.str()) << buildOptions;
356	}
357
358	if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT)
359	{
360		const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT);
361		std::ostringstream src;
362		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
363			<< extensions
364			<< "layout(location = 0) out highp vec4 fragColor;\n"
365			<< "\n"
366			<< (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
367			<< (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
368			<< (useSpecConst ? m_caseDef.globalCode + "\n" : "")
369			<< "void main (void)\n"
370			<< "{\n"
371			<< (useSpecConst ? m_caseDef.mainCode + "\n" : "")
372			<< "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
373			<< "}\n";
374
375		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()) << buildOptions;
376	}
377
378	if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
379	{
380		const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
381		std::ostringstream src;
382		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
383			<< extensions
384			<< "layout(vertices = 3) out;\n"
385			<< "\n"
386			<< "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
387			<< "\n"
388			<< "out " << s_perVertexBlock << " gl_out[];\n"
389			<< "\n"
390			<< (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
391			<< (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
392			<< (useSpecConst ? m_caseDef.globalCode + "\n" : "")
393			<< "void main (void)\n"
394			<< "{\n"
395			<< (useSpecConst ? m_caseDef.mainCode + "\n" : "")
396			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
397			<< "    if (gl_InvocationID == 0)\n"
398			<< "    {\n"
399			<< "        gl_TessLevelInner[0] = 3;\n"
400			<< "        gl_TessLevelOuter[0] = 2;\n"
401			<< "        gl_TessLevelOuter[1] = 2;\n"
402			<< "        gl_TessLevelOuter[2] = 2;\n"
403			<< "    }\n"
404			<< "}\n";
405
406		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()) << buildOptions;
407	}
408
409	if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
410	{
411		const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
412		std::ostringstream src;
413		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
414			<< extensions
415			<< "layout(triangles, equal_spacing, ccw) in;\n"
416			<< "\n"
417			<< "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
418			<< "\n"
419			<< "out " << s_perVertexBlock << ";\n"
420			<< "\n"
421			<< (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
422			<< (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
423			<< (useSpecConst ? m_caseDef.globalCode + "\n" : "")
424			<< "void main (void)\n"
425			<< "{\n"
426			<< (useSpecConst ? m_caseDef.mainCode + "\n" : "")
427			<< "    vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
428			<< "    vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
429			<< "    vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
430			<< "    gl_Position = vec4(p0 + p1 + p2, 1.0);\n"
431			<< "}\n";
432
433		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()) << buildOptions;
434	}
435
436	if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT)
437	{
438		const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT);
439		std::ostringstream src;
440		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
441			<< extensions
442			<< "layout(triangles) in;\n"
443			<< "layout(triangle_strip, max_vertices = 3) out;\n"
444			<< "\n"
445			<< "in " << s_perVertexBlock << " gl_in[];\n"
446			<< "\n"
447			<< "out " << s_perVertexBlock << ";\n"
448			<< "\n"
449			<< (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
450			<< (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
451			<< (useSpecConst ? m_caseDef.globalCode + "\n" : "")
452			<< "void main (void)\n"
453			<< "{\n"
454			<< (useSpecConst ? m_caseDef.mainCode + "\n" : "")
455			<< "    gl_Position = gl_in[0].gl_Position;\n"
456			<< "    EmitVertex();\n"
457			<< "\n"
458			<< "    gl_Position = gl_in[1].gl_Position;\n"
459			<< "    EmitVertex();\n"
460			<< "\n"
461			<< "    gl_Position = gl_in[2].gl_Position;\n"
462			<< "    EmitVertex();\n"
463			<< "\n"
464			<< "    EndPrimitive();\n"
465			<< "}\n";
466
467		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()) << buildOptions;
468	}
469
470	if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT)
471	{
472		std::ostringstream src;
473		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
474			<< extensions
475			// Don't define work group size, use the default or specialization constants
476			<< "\n"
477			<< generateSpecConstantCode(m_caseDef.specConstants)
478			<< generateSSBOCode(m_caseDef.ssboCode)
479			<< m_caseDef.globalCode + "\n"
480			<< "void main (void)\n"
481			<< "{\n"
482			<< m_caseDef.mainCode
483			<< "}\n";
484
485		programCollection.glslSources.add("comp") << glu::ComputeSource(src.str()) << buildOptions;
486	}
487}
488
489class ComputeTestInstance : public TestInstance
490{
491public:
492									ComputeTestInstance	(Context&							context,
493														 PipelineConstructionType			pipelineConstructionType,
494														 const VkDeviceSize					ssboSize,
495														 const std::vector<SpecConstant>&	specConstants,
496														 const std::vector<OffsetValue>&	expectedValues,
497														 bool								packData);
498
499	tcu::TestStatus					iterate				(void);
500
501private:
502	const PipelineConstructionType	m_pipelineConstructionType;
503	const VkDeviceSize				m_ssboSize;
504	const std::vector<SpecConstant>	m_specConstants;
505	const std::vector<OffsetValue>	m_expectedValues;
506	const bool						m_packData;
507};
508
509ComputeTestInstance::ComputeTestInstance (Context&							context,
510										  PipelineConstructionType			pipelineConstructionType,
511										  const VkDeviceSize				ssboSize,
512										  const std::vector<SpecConstant>&	specConstants,
513										  const std::vector<OffsetValue>&	expectedValues,
514										  bool								packData)
515	: TestInstance					(context)
516	, m_pipelineConstructionType	(pipelineConstructionType)
517	, m_ssboSize					(ssboSize)
518	, m_specConstants				(specConstants)
519	, m_expectedValues				(expectedValues)
520	, m_packData					(packData)
521{
522}
523
524tcu::TestStatus ComputeTestInstance::iterate (void)
525{
526	const DeviceInterface&	vk					= m_context.getDeviceInterface();
527	const VkDevice			device				= m_context.getDevice();
528	const VkQueue			queue				= m_context.getUniversalQueue();
529	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
530	Allocator&				allocator			= m_context.getDefaultAllocator();
531
532	// Descriptors
533
534	const BufferWithMemory resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
535
536	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
537		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
538		.build(vk, device));
539
540	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
541		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
542		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
543
544	const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
545	const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
546
547	DescriptorSetUpdateBuilder()
548		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
549		.update(vk, device);
550
551	// Specialization
552
553	const Specialization        specialization (m_specConstants, m_packData);
554	const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
555
556	// Pipeline
557
558	const PipelineLayoutWrapper		pipelineLayout	(m_pipelineConstructionType, vk, device, *descriptorSetLayout);
559	ComputePipelineWrapper			pipeline		(vk, device, graphicsToComputeConstructionType(m_pipelineConstructionType), m_context.getBinaryCollection().get("comp"));
560	pipeline.setDescriptorSetLayout(*descriptorSetLayout);
561	if (pSpecInfo)
562		pipeline.setSpecializationInfo(*pSpecInfo);
563	pipeline.buildPipeline();
564	const Unique<VkCommandPool>		cmdPool			(createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
565	const Unique<VkCommandBuffer>	cmdBuffer		(makeCommandBuffer		(vk, device, *cmdPool));
566
567	beginCommandBuffer(vk, *cmdBuffer);
568
569	pipeline.bind(*cmdBuffer);
570	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
571
572	vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
573
574	{
575		const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
576			VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
577
578		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
579			0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
580	}
581
582	endCommandBuffer(vk, *cmdBuffer);
583	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
584
585	// Verify results
586
587	const Allocation& resultAlloc = resultBuffer.getAllocation();
588	invalidateAlloc(vk, device, resultAlloc);
589
590	if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
591		return tcu::TestStatus::pass("Success");
592	else
593		return tcu::TestStatus::fail("Values did not match");
594}
595
596class GraphicsTestInstance : public TestInstance
597{
598public:
599									GraphicsTestInstance (Context&							context,
600														  const PipelineConstructionType	pipelineConstructionType,
601														  const VkDeviceSize				ssboSize,
602														  const std::vector<SpecConstant>&	specConstants,
603														  const std::vector<OffsetValue>&	expectedValues,
604														  const VkShaderStageFlagBits		stage,
605														  bool								packData);
606
607	tcu::TestStatus					iterate				 (void);
608
609private:
610	const PipelineConstructionType	m_pipelineConstructionType;
611	const VkDeviceSize				m_ssboSize;
612	const std::vector<SpecConstant>	m_specConstants;
613	const std::vector<OffsetValue>	m_expectedValues;
614	const VkShaderStageFlagBits		m_stage;
615	const bool						m_packData;
616};
617
618GraphicsTestInstance::GraphicsTestInstance (Context&							context,
619											const PipelineConstructionType		pipelineConstructionType,
620											const VkDeviceSize					ssboSize,
621											const std::vector<SpecConstant>&	specConstants,
622											const std::vector<OffsetValue>&		expectedValues,
623											const VkShaderStageFlagBits			stage,
624											bool								packData)
625	: TestInstance					(context)
626	, m_pipelineConstructionType	(pipelineConstructionType)
627	, m_ssboSize					(ssboSize)
628	, m_specConstants				(specConstants)
629	, m_expectedValues				(expectedValues)
630	, m_stage						(stage)
631	, m_packData					(packData)
632{
633}
634
635tcu::TestStatus GraphicsTestInstance::iterate (void)
636{
637	const InstanceInterface&	vki					= m_context.getInstanceInterface();
638	const DeviceInterface&		vk					= m_context.getDeviceInterface();
639	const VkPhysicalDevice		physicalDevice		= m_context.getPhysicalDevice();
640	const VkDevice				device				= m_context.getDevice();
641	const VkQueue				queue				= m_context.getUniversalQueue();
642	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
643	Allocator&					allocator			= m_context.getDefaultAllocator();
644
645	// Color attachment
646
647	const tcu::IVec2          renderSize    = tcu::IVec2(32, 32);
648	const VkFormat            imageFormat   = VK_FORMAT_R8G8B8A8_UNORM;
649	const ImageWithMemory     colorImage    (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any);
650	const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)));
651
652	// Vertex buffer
653
654	const deUint32			numVertices           = 3;
655	const VkDeviceSize		vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices;
656	const BufferWithMemory	vertexBuffer          (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
657
658	{
659		const Allocation& alloc = vertexBuffer.getAllocation();
660		tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr());
661
662		pVertices[0] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
663		pVertices[1] = tcu::Vec4(-1.0f,  1.0f,  0.0f,  1.0f);
664		pVertices[2] = tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f);
665
666		flushAlloc(vk, device, alloc);
667		// No barrier needed, flushed memory is automatically visible
668	}
669
670	// Descriptors
671
672	const BufferWithMemory resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
673
674	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
675		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS)
676		.build(vk, device));
677
678	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
679		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
680		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
681
682	const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
683	const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
684
685	DescriptorSetUpdateBuilder()
686		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
687		.update(vk, device);
688
689	// Specialization
690
691	const Specialization        specialization (m_specConstants, m_packData);
692	const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
693
694	// Pipeline
695
696	RenderPassWrapper				renderPass		(m_pipelineConstructionType, vk, device, imageFormat);
697	renderPass.createFramebuffer(vk, device, colorImage.get(), colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y()));
698	const PipelineLayoutWrapper		pipelineLayout	(m_pipelineConstructionType, vk, device, *descriptorSetLayout);
699	const Unique<VkCommandPool>		cmdPool			(createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
700	const Unique<VkCommandBuffer>	cmdBuffer		(makeCommandBuffer (vk, device, *cmdPool));
701
702	vk::BinaryCollection&			binaryCollection(m_context.getBinaryCollection());
703	VkPrimitiveTopology				topology		(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
704	const std::vector<VkViewport>	viewport		{ makeViewport(renderSize) };
705	const std::vector<VkRect2D>		scissor			{ makeRect2D(renderSize) };
706
707	ShaderWrapper vertShaderModule	= ShaderWrapper(vk, device, binaryCollection.get("vert"), 0u);
708	ShaderWrapper tescShaderModule;
709	ShaderWrapper teseShaderModule;
710	ShaderWrapper geomShaderModule;
711	ShaderWrapper fragShaderModule	= ShaderWrapper(vk, device, binaryCollection.get("frag"), 0u);
712
713	if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
714	{
715		tescShaderModule	= ShaderWrapper(vk, device, binaryCollection.get("tesc"), 0u);
716		teseShaderModule	= ShaderWrapper(vk, device, binaryCollection.get("tese"), 0u);
717		topology			= VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
718	}
719	if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT)
720		geomShaderModule = ShaderWrapper(vk, device, binaryCollection.get("geom"), 0u);
721
722	GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_pipelineConstructionType);
723	graphicsPipeline.setDefaultRasterizationState()
724					.setDefaultDepthStencilState()
725					.setDefaultMultisampleState()
726					.setDefaultColorBlendState()
727					.setDefaultTopology(topology)
728					.setupVertexInputState()
729					.setupPreRasterizationShaderState(viewport,
730													  scissor,
731													  pipelineLayout,
732													  *renderPass,
733													  0u,
734													  vertShaderModule,
735													  0u,
736													  tescShaderModule,
737													  teseShaderModule,
738													  geomShaderModule,
739													  pSpecInfo)
740					.setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShaderModule, DE_NULL, DE_NULL, pSpecInfo)
741					.setupFragmentOutputState(*renderPass)
742					.setMonolithicPipelineLayout(pipelineLayout)
743					.buildPipeline();
744
745	// Draw commands
746
747	const VkRect2D		renderArea			= makeRect2D(renderSize);
748	const tcu::Vec4		clearColor			(0.0f, 0.0f, 0.0f, 1.0f);
749	const VkDeviceSize	vertexBufferOffset	= 0ull;
750
751	beginCommandBuffer(vk, *cmdBuffer);
752
753	{
754		const VkImageSubresourceRange imageFullSubresourceRange              = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
755		const VkImageMemoryBarrier    barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier(
756			0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
757			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
758			*colorImage, imageFullSubresourceRange);
759
760		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
761			0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout);
762	}
763
764	renderPass.begin(vk, *cmdBuffer, renderArea, clearColor);
765
766	graphicsPipeline.bind(*cmdBuffer);
767	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
768	vk.cmdBindVertexBuffers (*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
769
770	vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
771	renderPass.end(vk, *cmdBuffer);
772
773	{
774		const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
775			VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
776
777		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
778			0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
779	}
780
781	endCommandBuffer(vk, *cmdBuffer);
782	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
783
784	// Verify results
785
786	const Allocation& resultAlloc = resultBuffer.getAllocation();
787	invalidateAlloc(vk, device, resultAlloc);
788
789	if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
790		return tcu::TestStatus::pass("Success");
791	else
792		return tcu::TestStatus::fail("Values did not match");
793}
794
795FeatureFlags getShaderStageRequirements (const VkShaderStageFlags stageFlags)
796{
797	FeatureFlags features = (FeatureFlags)0;
798
799	if (((stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) || ((stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0))
800		features |= FEATURE_TESSELLATION_SHADER;
801
802	if ((stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0)
803		features |= FEATURE_GEOMETRY_SHADER;
804
805	// All tests use SSBO writes to read back results.
806	if ((stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) != 0)
807	{
808		if ((stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0)
809			features |= FEATURE_FRAGMENT_STORES_AND_ATOMICS;
810		else
811			features |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS;
812	}
813
814	return features;
815}
816
817void SpecConstantTest::checkSupport (Context& context) const
818{
819	requireFeatures(context, m_caseDef.requirements | getShaderStageRequirements(m_stage));
820	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
821}
822
823TestInstance* SpecConstantTest::createInstance (Context& context) const
824{
825	if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT)
826		return new ComputeTestInstance(context, m_pipelineConstructionType, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_caseDef.packData);
827	else
828		return new GraphicsTestInstance(context, m_pipelineConstructionType, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_stage, m_caseDef.packData);
829}
830
831//! Declare specialization constants but use them with default values.
832tcu::TestCaseGroup* createDefaultValueTests (tcu::TestContext& testCtx, const PipelineConstructionType pipelineType, const VkShaderStageFlagBits shaderStage)
833{
834	// use default constant value
835	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "default_value"));
836
837	CaseDefinition defs[] =
838	{
839		{
840			"bool",
841			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;"),
842					   SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;")),
843			8,
844			"    bool r0;\n"
845			"    bool r1;\n",
846			"",
847			"    sb_out.r0 = sc0;\n"
848			"    sb_out.r1 = sc1;\n",
849			makeVector(OffsetValue(4, 0, makeValueBool32(true)),
850					   OffsetValue(4, 4, makeValueBool32(false))),
851			(FeatureFlags)0,
852			false,
853		},
854		{
855			"int8",
856			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(1);"),
857					   SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-2);")),
858			2,
859			"    int8_t r0;\n"
860			"    int8_t r1;\n",
861			"",
862			"    int8_t aux = sc0 + sc1;\n"
863			"    sb_out.r0 = sc0;\n"
864			"    sb_out.r1 = sc1;\n",
865			makeVector(OffsetValue(1, 0, makeValueInt8(1)),
866					   OffsetValue(1, 1, makeValueInt8(-2))),
867			FEATURE_SHADER_INT_8,
868			false,
869		},
870		{
871			"uint8",
872			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(15);"),
873					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(43);")),
874			2,
875			"    uint8_t r0;\n"
876			"    uint8_t r1;\n",
877			"",
878			"    uint8_t aux = sc0 + sc1;\n"
879			"    sb_out.r0 = sc0;\n"
880			"    sb_out.r1 = sc1;\n",
881			makeVector(OffsetValue(1, 0, makeValueUint8(15)),
882					   OffsetValue(1, 1, makeValueUint8(43))),
883			FEATURE_SHADER_INT_8,
884			false,
885		},
886		{
887			"int16",
888			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
889					   SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;")),
890			4,
891			"    int16_t r0;\n"
892			"    int16_t r1;\n",
893			"",
894			"    int16_t aux = sc0 + sc1;\n"
895			"    sb_out.r0 = sc0;\n"
896			"    sb_out.r1 = sc1;\n",
897			makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
898					   OffsetValue(2, 2, makeValueInt16(-20000))),
899			FEATURE_SHADER_INT_16,
900			false,
901		},
902		{
903			"uint16",
904			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;"),
905					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;")),
906			4,
907			"    uint16_t r0;\n"
908			"    uint16_t r1;\n",
909			"",
910			"    uint16_t aux = sc0 + sc1;\n"
911			"    sb_out.r0 = sc0;\n"
912			"    sb_out.r1 = sc1;\n",
913			makeVector(OffsetValue(2, 0, makeValueUint16(64000)),
914					   OffsetValue(2, 2, makeValueUint16(51829))),
915			FEATURE_SHADER_INT_16,
916			false,
917		},
918		{
919			"int",
920			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;"),
921					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 17;")),
922			8,
923			"    int r0;\n"
924			"    int r1;\n",
925			"",
926			"    sb_out.r0 = sc0;\n"
927			"    sb_out.r1 = sc1;\n",
928			makeVector(OffsetValue(4, 0, makeValueInt32(-3)),
929					   OffsetValue(4, 4, makeValueInt32(17))),
930			(FeatureFlags)0,
931			false,
932		},
933		{
934			"uint",
935			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;")),
936			4,
937			"    uint r0;\n",
938			"",
939			"    sb_out.r0 = sc0;\n",
940			makeVector(OffsetValue(4, 0, makeValueUint32(42u))),
941			(FeatureFlags)0,
942			false,
943		},
944		{
945			"int64",
946			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;"),
947					   SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;")),
948			16,
949			"    int64_t r0;\n"
950			"    int64_t r1;\n",
951			"",
952			"    sb_out.r0 = sc0;\n"
953			"    sb_out.r1 = sc1;\n",
954			makeVector(OffsetValue(8, 0, makeValueInt64(9141386509785772560ll)),
955					   OffsetValue(8, 8, makeValueInt64(-9141386509785772560ll))),
956			FEATURE_SHADER_INT_64,
957			false,
958		},
959		{
960			"uint64",
961			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;"),
962					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;")),
963			16,
964			"    uint64_t r0;\n"
965			"    uint64_t r1;\n",
966			"",
967			"    sb_out.r0 = sc0;\n"
968			"    sb_out.r1 = sc1;\n",
969			makeVector(OffsetValue(8, 0, makeValueUint64(18364758544493064720ull)),
970					   OffsetValue(8, 8, makeValueUint64(17298946664678735070ull))),
971			FEATURE_SHADER_INT_64,
972			false,
973		},
974		{
975			"float16",
976			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;"),
977					   SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;")),
978			4,
979			"    float16_t r0;\n"
980			"    float16_t r1;\n",
981			"",
982			"    float16_t aux = sc0 + sc1;\n"
983			"    sb_out.r0 = sc0;\n"
984			"    sb_out.r1 = sc1;\n",
985			makeVector(OffsetValue(2, 0, makeValueFloat16(tcu::Float16(7.5))),
986					   OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125)))),
987			FEATURE_SHADER_FLOAT_16,
988			false,
989		},
990		{
991			"float",
992			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;")),
993			4,
994			"    float r0;\n",
995			"",
996			"    sb_out.r0 = sc0;\n",
997			makeVector(OffsetValue(4, 0, makeValueFloat32(7.5f))),
998			(FeatureFlags)0,
999			false,
1000		},
1001		{
1002			"double",
1003			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;")),
1004			8,
1005			"    double r0;\n",
1006			"",
1007			"    sb_out.r0 = sc0;\n",
1008			makeVector(OffsetValue(8, 0, makeValueFloat64(2.75))),
1009			FEATURE_SHADER_FLOAT_64,
1010			false,
1011		},
1012	};
1013
1014	for (int i = 0; i < 2; ++i)
1015	{
1016		const bool packData = (i > 0);
1017		for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1018		{
1019			auto& def = defs[defNdx];
1020			def.packData = packData;
1021			if (packData)
1022				def.name += "_packed";
1023			testGroup->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, def));
1024		}
1025	}
1026
1027	return testGroup.release();
1028}
1029
1030//! Declare specialization constants and specify their values through API.
1031tcu::TestCaseGroup* createBasicSpecializationTests (tcu::TestContext& testCtx, const PipelineConstructionType pipelineType, const VkShaderStageFlagBits shaderStage)
1032{
1033	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "basic", "specialize a constant"));
1034
1035	CaseDefinition defs[] =
1036	{
1037		{
1038			"bool",
1039			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;",  4, makeValueBool32(true)),
1040					   SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;", 4, makeValueBool32(false)),
1041					   SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;",  4, makeValueBool32(false)),
1042					   SpecConstant(4u, "layout(constant_id = ${ID}) const bool sc3 = false;", 4, makeValueBool32(true))),
1043			16,
1044			"    bool r0;\n"
1045			"    bool r1;\n"
1046			"    bool r2;\n"
1047			"    bool r3;\n",
1048			"",
1049			"    sb_out.r0 = sc0;\n"
1050			"    sb_out.r1 = sc1;\n"
1051			"    sb_out.r2 = sc2;\n"
1052			"    sb_out.r3 = sc3;\n",
1053			makeVector(OffsetValue(4,  0, makeValueBool32(true)),
1054					   OffsetValue(4,  4, makeValueBool32(false)),
1055					   OffsetValue(4,  8, makeValueBool32(false)),
1056					   OffsetValue(4, 12, makeValueBool32(true))),
1057			(FeatureFlags)0,
1058			false,
1059		},
1060		{
1061			"int8",
1062			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(1);", 1, makeValueInt8(127)),
1063					   SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-2);")),
1064			2,
1065			"    int8_t r0;\n"
1066			"    int8_t r1;\n",
1067			"",
1068			"    int8_t aux = sc0 + sc1;\n"
1069			"    sb_out.r0 = sc0;\n"
1070			"    sb_out.r1 = sc1;\n",
1071			makeVector(OffsetValue(1, 0, makeValueInt8(127)),
1072					   OffsetValue(1, 1, makeValueInt8(-2))),
1073			FEATURE_SHADER_INT_8,
1074			false,
1075		},
1076		{
1077			"int8_2",
1078			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(123);", 1, makeValueInt8(65)),
1079					   SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-33);", 1, makeValueInt8(-128))),
1080			2,
1081			"    int8_t r0;\n"
1082			"    int8_t r1;\n",
1083			"",
1084			"    int8_t aux = sc0 + sc1;\n"
1085			"    sb_out.r0 = sc0;\n"
1086			"    sb_out.r1 = sc1;\n",
1087			makeVector(OffsetValue(1, 0, makeValueInt8(65)),
1088					   OffsetValue(1, 1, makeValueInt8(-128))),
1089			FEATURE_SHADER_INT_8,
1090			false,
1091		},
1092		{
1093			"uint8",
1094			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(15);", 1, makeValueUint8(254)),
1095					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(43);")),
1096			2,
1097			"    uint8_t r0;\n"
1098			"    uint8_t r1;\n",
1099			"",
1100			"    uint8_t aux = sc0 + sc1;\n"
1101			"    sb_out.r0 = sc0;\n"
1102			"    sb_out.r1 = sc1;\n",
1103			makeVector(OffsetValue(1, 0, makeValueUint8(254)),
1104					   OffsetValue(1, 1, makeValueUint8(43))),
1105			FEATURE_SHADER_INT_8,
1106			false,
1107		},
1108		{
1109			"uint8_2",
1110			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(99);", 1, makeValueUint8(254)),
1111					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(81);", 1, makeValueUint8(255))),
1112			2,
1113			"    uint8_t r0;\n"
1114			"    uint8_t r1;\n",
1115			"",
1116			"    uint8_t aux = sc0 + sc1;\n"
1117			"    sb_out.r0 = sc0;\n"
1118			"    sb_out.r1 = sc1;\n",
1119			makeVector(OffsetValue(1, 0, makeValueUint8(254)),
1120					   OffsetValue(1, 1, makeValueUint8(255))),
1121			FEATURE_SHADER_INT_8,
1122			false,
1123		},
1124		{
1125			"int16",
1126			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
1127					   SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;")),
1128			4,
1129			"    int16_t r0;\n"
1130			"    int16_t r1;\n",
1131			"",
1132			"    int16_t aux = sc0 + sc1;\n"
1133			"    sb_out.r0 = sc0;\n"
1134			"    sb_out.r1 = sc1;\n",
1135			makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
1136					   OffsetValue(2, 2, makeValueInt16(-20000))),
1137			FEATURE_SHADER_INT_16,
1138			false,
1139		},
1140		{
1141			"int16_2",
1142			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
1143					   SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;", 2, makeValueInt16(-21000))),
1144			4,
1145			"    int16_t r0;\n"
1146			"    int16_t r1;\n",
1147			"",
1148			"    int16_t aux = sc0 + sc1;\n"
1149			"    sb_out.r0 = sc0;\n"
1150			"    sb_out.r1 = sc1;\n",
1151			makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
1152					   OffsetValue(2, 2, makeValueInt16(-21000))),
1153			FEATURE_SHADER_INT_16,
1154			false,
1155		},
1156		{
1157			"uint16",
1158			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;", 2, makeValueUint16(65000)),
1159					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;")),
1160			4,
1161			"    uint16_t r0;\n"
1162			"    uint16_t r1;\n",
1163			"",
1164			"    uint16_t aux = sc0 + sc1;\n"
1165			"    sb_out.r0 = sc0;\n"
1166			"    sb_out.r1 = sc1;\n",
1167			makeVector(OffsetValue(2, 0, makeValueUint16(65000)),
1168					   OffsetValue(2, 2, makeValueUint16(51829))),
1169			FEATURE_SHADER_INT_16,
1170			false,
1171		},
1172		{
1173			"uint16_2",
1174			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;", 2, makeValueUint16(65000)),
1175					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;", 2, makeValueUint16(63000))),
1176			4,
1177			"    uint16_t r0;\n"
1178			"    uint16_t r1;\n",
1179			"",
1180			"    uint16_t aux = sc0 + sc1;\n"
1181			"    sb_out.r0 = sc0;\n"
1182			"    sb_out.r1 = sc1;\n",
1183			makeVector(OffsetValue(2, 0, makeValueUint16(65000)),
1184					   OffsetValue(2, 2, makeValueUint16(63000))),
1185			FEATURE_SHADER_INT_16,
1186			false,
1187		},
1188		{
1189			"int",
1190			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;", 4, makeValueInt32(33)),
1191					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 91;"),
1192					   SpecConstant(3u, "layout(constant_id = ${ID}) const int sc2 = 17;", 4, makeValueInt32(-15))),
1193			12,
1194			"    int r0;\n"
1195			"    int r1;\n"
1196			"    int r2;\n",
1197			"",
1198			"    sb_out.r0 = sc0;\n"
1199			"    sb_out.r1 = sc1;\n"
1200			"    sb_out.r2 = sc2;\n",
1201			makeVector(OffsetValue(4, 0, makeValueInt32(33)),
1202					   OffsetValue(4, 4, makeValueInt32(91)),
1203					   OffsetValue(4, 8, makeValueInt32(-15))),
1204			(FeatureFlags)0,
1205			false,
1206		},
1207		{
1208			"uint",
1209			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;", 4, makeValueUint32(97u)),
1210					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 7u;")),
1211			8,
1212			"    uint r0;\n"
1213			"    uint r1;\n",
1214			"",
1215			"    sb_out.r0 = sc0;\n"
1216			"    sb_out.r1 = sc1;\n",
1217			makeVector(OffsetValue(4, 0, makeValueUint32(97u)),
1218					   OffsetValue(4, 4, makeValueUint32(7u))),
1219			(FeatureFlags)0,
1220			false,
1221		},
1222		{
1223			"uint_2",
1224			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 305419896u;", 4, makeValueUint32(1985229328u)),
1225					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 591751049u;"),
1226					   SpecConstant(3u, "layout(constant_id = ${ID}) const uint sc2 = 878082202u;", 4, makeValueUint32(1698898186u))),
1227			12,
1228			"    uint r0;\n"
1229			"    uint r1;\n"
1230			"    uint r2;\n",
1231			"",
1232			"    sb_out.r0 = sc0;\n"
1233			"    sb_out.r1 = sc1;\n"
1234			"    sb_out.r2 = sc2;\n",
1235			makeVector(OffsetValue(4, 0, makeValueUint32(1985229328u)),
1236					   OffsetValue(4, 4, makeValueUint32(591751049u)),
1237					   OffsetValue(4, 8, makeValueUint32(1698898186u))),
1238			(FeatureFlags)0,
1239			false,
1240		},
1241		{
1242			"int64",
1243			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;", 8, makeValueInt64(9137147825770275585ll)),
1244					   SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;")),
1245			16,
1246			"    int64_t r0;\n"
1247			"    int64_t r1;\n",
1248			"",
1249			"    sb_out.r0 = sc0;\n"
1250			"    sb_out.r1 = sc1;\n",
1251			makeVector(OffsetValue(8, 0, makeValueInt64(9137147825770275585ll)),
1252					   OffsetValue(8, 8, makeValueInt64(-9141386509785772560ll))),
1253			FEATURE_SHADER_INT_64,
1254			false,
1255		},
1256		{
1257			"int64_2",
1258			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;", 8, makeValueInt64(9137147825770275585ll)),
1259					   SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;", 8, makeValueInt64(-9137164382869201665ll))),
1260			16,
1261			"    int64_t r0;\n"
1262			"    int64_t r1;\n",
1263			"",
1264			"    sb_out.r0 = sc0;\n"
1265			"    sb_out.r1 = sc1;\n",
1266			makeVector(OffsetValue(8, 0, makeValueInt64(9137147825770275585ll)),
1267					   OffsetValue(8, 8, makeValueInt64(-9137164382869201665ll))),
1268			FEATURE_SHADER_INT_64,
1269			false,
1270		},
1271		{
1272			"uint64",
1273			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;", 8, makeValueUint64(17279655951921914625ull)),
1274					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;")),
1275			16,
1276			"    uint64_t r0;\n"
1277			"    uint64_t r1;\n",
1278			"",
1279			"    sb_out.r0 = sc0;\n"
1280			"    sb_out.r1 = sc1;\n",
1281			makeVector(OffsetValue(8, 0, makeValueUint64(17279655951921914625ull)),
1282					   OffsetValue(8, 8, makeValueUint64(17298946664678735070ull))),
1283			FEATURE_SHADER_INT_64,
1284			false,
1285		},
1286		{
1287			"uint64_2",
1288			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;", 8, makeValueUint64(17279655951921914625ull)),
1289					   SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;", 8, makeValueUint64(17270123250533606145ull))),
1290			16,
1291			"    uint64_t r0;\n"
1292			"    uint64_t r1;\n",
1293			"",
1294			"    sb_out.r0 = sc0;\n"
1295			"    sb_out.r1 = sc1;\n",
1296			makeVector(OffsetValue(8, 0, makeValueUint64(17279655951921914625ull)),
1297					   OffsetValue(8, 8, makeValueUint64(17270123250533606145ull))),
1298			FEATURE_SHADER_INT_64,
1299			false,
1300		},
1301		// We create some floating point values below as unsigned integers to make sure all bytes are set to different values, avoiding special patterns and denormals.
1302		{
1303			"float16",
1304			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;", 2, makeValueFloat16(tcu::Float16(15.75))),
1305					   SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;")),
1306			4,
1307			"    float16_t r0;\n"
1308			"    float16_t r1;\n",
1309			"",
1310			"    float16_t aux = sc0 + sc1;\n"
1311			"    sb_out.r0 = sc0;\n"
1312			"    sb_out.r1 = sc1;\n",
1313			makeVector(OffsetValue(2, 0, makeValueFloat16(tcu::Float16(15.75))),
1314					   OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125)))),
1315			FEATURE_SHADER_FLOAT_16,
1316			false,
1317		},
1318		{
1319			"float16_2",
1320			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;", 2, makeValueUint16(0x0123u)),
1321					   SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;"),
1322					   SpecConstant(3u, "layout(constant_id = ${ID}) const float16_t sc2 = 1.125hf;", 2, makeValueUint16(0xFEDCu))),
1323			6,
1324			"    float16_t r0;\n"
1325			"    float16_t r1;\n"
1326			"    float16_t r2;\n",
1327			"",
1328			"    float16_t aux = sc0 + sc1;\n"
1329			"    sb_out.r0 = sc0;\n"
1330			"    sb_out.r1 = sc1;\n"
1331			"    sb_out.r2 = sc2;\n",
1332			makeVector(OffsetValue(2, 0, makeValueUint16(0x0123u)),
1333					   OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125))),
1334					   OffsetValue(2, 4, makeValueUint16(0xFEDCu))),
1335			FEATURE_SHADER_FLOAT_16,
1336			false,
1337		},
1338		{
1339			"float",
1340			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueFloat32(15.75f)),
1341					   SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;")),
1342			8,
1343			"    float r0;\n"
1344			"    float r1;\n",
1345			"",
1346			"    sb_out.r0 = sc0;\n"
1347			"    sb_out.r1 = sc1;\n",
1348			makeVector(OffsetValue(4, 0, makeValueFloat32(15.75f)),
1349					   OffsetValue(4, 4, makeValueFloat32(1.125f))),
1350			(FeatureFlags)0,
1351			false,
1352		},
1353		{
1354			"float_2",
1355			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueUint32(0x01234567u)),
1356					   SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;"),
1357					   SpecConstant(3u, "layout(constant_id = ${ID}) const float sc2 = 1.125;", 4, makeValueUint32(0xfedcba98u))),
1358			12,
1359			"    float r0;\n"
1360			"    float r1;\n"
1361			"    float r2;\n",
1362			"",
1363			"    sb_out.r0 = sc0;\n"
1364			"    sb_out.r1 = sc1;\n"
1365			"    sb_out.r2 = sc2;\n",
1366			makeVector(OffsetValue(4, 0, makeValueUint32(0x01234567u)),
1367					   OffsetValue(4, 4, makeValueFloat32(1.125f)),
1368					   OffsetValue(4, 8, makeValueUint32(0xfedcba98u))),
1369			(FeatureFlags)0,
1370			false,
1371		},
1372		{
1373			"double",
1374			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueUint64(0xFEDCBA9876543210ull)),
1375					   SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;")),
1376			16,
1377			"    double r0;\n"
1378			"    double r1;\n",
1379			"",
1380			"    sb_out.r0 = sc0;\n"
1381			"    sb_out.r1 = sc1;\n",
1382			makeVector(OffsetValue(8, 0, makeValueUint64(0xFEDCBA9876543210ull)),
1383					   OffsetValue(8, 8, makeValueFloat64(9.25))),
1384			FEATURE_SHADER_FLOAT_64,
1385			false,
1386		},
1387		{
1388			"double_2",
1389			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueUint64(0xFEDCBA9876543210ull)),
1390					   SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;", 8, makeValueUint64(0xEFCDAB8967452301ull))),
1391			16,
1392			"    double r0;\n"
1393			"    double r1;\n",
1394			"",
1395			"    sb_out.r0 = sc0;\n"
1396			"    sb_out.r1 = sc1;\n",
1397			makeVector(OffsetValue(8, 0, makeValueUint64(0xFEDCBA9876543210ull)),
1398					   OffsetValue(8, 8, makeValueUint64(0xEFCDAB8967452301ull))),
1399			FEATURE_SHADER_FLOAT_64,
1400			false,
1401		},
1402		{
1403			"mixed",
1404			makeVector(
1405				SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t  sc0 = uint8_t  (0);", 1, makeValueUint8(0x98)),
1406				SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = uint16_t (0);", 2, makeValueUint16(0x9876)),
1407				SpecConstant(3u, "layout(constant_id = ${ID}) const uint     sc2 = uint     (0);", 4, makeValueUint32(0xba987654u)),
1408				SpecConstant(4u, "layout(constant_id = ${ID}) const uint64_t sc3 = uint64_t (0);", 8, makeValueUint64(0xfedcba9876543210ull))),
1409			8+4+2+1,
1410			"    uint64_t r0;\n"
1411			"    uint     r1;\n"
1412			"    uint16_t r2;\n"
1413			"    uint8_t  r3;\n",
1414			"",
1415			"    uint64_t i0 = sc3;\n"
1416			"    uint     i1 = sc2;\n"
1417			"    uint16_t i2 = sc1;\n"
1418			"    uint8_t  i3 = sc0;\n"
1419			"    sb_out.r0 = i0;\n"
1420			"    sb_out.r1 = i1;\n"
1421			"    sb_out.r2 = i2;\n"
1422			"    sb_out.r3 = i3;\n",
1423			makeVector(
1424				OffsetValue(8, 0, makeValueUint64(0xfedcba9876543210ull)),
1425				OffsetValue(4, 8, makeValueUint32(0xba987654u)),
1426				OffsetValue(2, 12, makeValueUint16(0x9876)),
1427				OffsetValue(1, 14, makeValueUint8(0x98))),
1428			(FEATURE_SHADER_INT_8 | FEATURE_SHADER_INT_16 | FEATURE_SHADER_INT_64),
1429			false,
1430		},
1431		{
1432			"mixed_reversed",
1433			makeVector(
1434				SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc3 = uint64_t (0);", 8, makeValueUint64(0xfedcba9876543210ull)),
1435				SpecConstant(2u, "layout(constant_id = ${ID}) const uint     sc2 = uint     (0);", 4, makeValueUint32(0xba987654u)),
1436				SpecConstant(3u, "layout(constant_id = ${ID}) const uint16_t sc1 = uint16_t (0);", 2, makeValueUint16(0x9876)),
1437				SpecConstant(4u, "layout(constant_id = ${ID}) const uint8_t  sc0 = uint8_t  (0);", 1, makeValueUint8(0x98))),
1438			8+4+2+1,
1439			"    uint64_t r0;\n"
1440			"    uint     r1;\n"
1441			"    uint16_t r2;\n"
1442			"    uint8_t  r3;\n",
1443			"",
1444			"    uint64_t i0 = sc3;\n"
1445			"    uint     i1 = sc2;\n"
1446			"    uint16_t i2 = sc1;\n"
1447			"    uint8_t  i3 = sc0;\n"
1448			"    sb_out.r0 = i0;\n"
1449			"    sb_out.r1 = i1;\n"
1450			"    sb_out.r2 = i2;\n"
1451			"    sb_out.r3 = i3;\n",
1452			makeVector(
1453				OffsetValue(8, 0, makeValueUint64(0xfedcba9876543210ull)),
1454				OffsetValue(4, 8, makeValueUint32(0xba987654u)),
1455				OffsetValue(2, 12, makeValueUint16(0x9876)),
1456				OffsetValue(1, 14, makeValueUint8(0x98))),
1457			(FEATURE_SHADER_INT_8 | FEATURE_SHADER_INT_16 | FEATURE_SHADER_INT_64),
1458			false,
1459		},
1460	};
1461
1462	for (int i = 0; i < 2; ++i)
1463	{
1464		const bool packData = (i > 0);
1465		for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1466		{
1467			auto& def = defs[defNdx];
1468			def.packData = packData;
1469			if (packData)
1470				def.name += "_packed";
1471			testGroup->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, def));
1472		}
1473	}
1474
1475	CaseDefinition defsUnusedCases[] =
1476	{
1477		{
1478			"unused_single",
1479			makeVector(SpecConstant(0u, "", 0u, GenericValue(), true)),
1480			4,
1481			"    int r0;\n",
1482			"",
1483			"    sb_out.r0 = 77;\n",
1484			makeVector(OffsetValue(4u, 0u, makeValueInt32(77))),
1485			(FeatureFlags)0,
1486			false,
1487		},
1488		{
1489			"unused_single_packed",
1490			makeVector(SpecConstant(0u, "", 0u, GenericValue(), true),
1491					   SpecConstant(1u, "layout(constant_id = ${ID}) const int sc1 = 0;", 4u, makeValueInt32(100))),
1492			4,
1493			"    int r1;\n",
1494			"",
1495			"    sb_out.r1 = sc1;\n",
1496			makeVector(OffsetValue(4u, 0u, makeValueInt32(100))),
1497			(FeatureFlags)0,
1498			true,
1499		},
1500		{
1501			"unused_multiple",
1502			makeVector(SpecConstant( 7u, "layout(constant_id = ${ID}) const int sc0 = 0;", 4u, makeValueInt32(-999)),
1503					   SpecConstant( 1u, "", 0u, GenericValue(), true),
1504					   SpecConstant(17u, "layout(constant_id = ${ID}) const int sc1 = 0;", 4u, makeValueInt32( 999)),
1505					   SpecConstant( 3u, "", 0u, GenericValue(), true)),
1506			8,
1507			"    int r0;\n"
1508			"    int r1;\n",
1509			"",
1510			"    sb_out.r0 = sc0;\n"
1511			"    sb_out.r1 = sc1;\n",
1512			makeVector(OffsetValue(4, 0, makeValueInt32(-999)),
1513					   OffsetValue(4, 4, makeValueInt32( 999))),
1514			(FeatureFlags)0,
1515			false,
1516		},
1517		{
1518			"unused_multiple_packed",
1519			makeVector(SpecConstant( 7u, "layout(constant_id = ${ID}) const int sc0 = 0;", 4u, makeValueInt32(-999)),
1520					   SpecConstant( 1u, "", 0u, GenericValue(), true),
1521					   SpecConstant( 3u, "", 0u, GenericValue(), true),
1522					   SpecConstant(17u, "layout(constant_id = ${ID}) const int sc1 = 0;", 4u, makeValueInt32( 999))),
1523			8,
1524			"    int r0;\n"
1525			"    int r1;\n",
1526			"",
1527			"    sb_out.r0 = sc0;\n"
1528			"    sb_out.r1 = sc1;\n",
1529			makeVector(OffsetValue(4, 0, makeValueInt32(-999)),
1530					   OffsetValue(4, 4, makeValueInt32( 999))),
1531			(FeatureFlags)0,
1532			true,
1533		},
1534	};
1535
1536	for (const auto& caseDef : defsUnusedCases)
1537		testGroup->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, caseDef));
1538
1539	return testGroup.release();
1540}
1541
1542//! Specify compute shader work group size through specialization constants.
1543tcu::TestCaseGroup* createWorkGroupSizeTests (tcu::TestContext& testCtx)
1544{
1545	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "local_size", "work group size specialization"));
1546
1547	const deUint32 ssboSize = 16;
1548	const std::string ssboDecl =
1549		"    uvec3 workGroupSize;\n"
1550		"    uint  checksum;\n";
1551	const std::string globalDecl = "shared uint count;\n";
1552	const std::string mainCode =
1553		"    count = 0u;\n"
1554		"\n"
1555		"    groupMemoryBarrier();\n"
1556		"    barrier();\n"
1557		"\n"
1558		"    atomicAdd(count, 1u);\n"
1559		"\n"
1560		"    groupMemoryBarrier();\n"
1561		"    barrier();\n"
1562		"\n"
1563		"    sb_out.workGroupSize = gl_WorkGroupSize;\n"
1564		"    sb_out.checksum      = count;\n";
1565
1566	const CaseDefinition defs[] =
1567	{
1568		{
1569			"x",
1570			makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(7u))),
1571			ssboSize, ssboDecl, globalDecl, mainCode,
1572			makeVector(OffsetValue(4,  0, makeValueUint32(7u)),
1573					   OffsetValue(4,  4, makeValueUint32(1u)),
1574					   OffsetValue(4,  8, makeValueUint32(1u)),
1575					   OffsetValue(4, 12, makeValueUint32(7u))),
1576			(FeatureFlags)0,
1577			false,
1578		},
1579		{
1580			"y",
1581			makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u))),
1582			ssboSize, ssboDecl, globalDecl, mainCode,
1583			makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1584					   OffsetValue(4,  4, makeValueUint32(5u)),
1585					   OffsetValue(4,  8, makeValueUint32(1u)),
1586					   OffsetValue(4, 12, makeValueUint32(5u))),
1587			(FeatureFlags)0,
1588			false,
1589		},
1590		{
1591			"z",
1592			makeVector(SpecConstant(1u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(3u))),
1593			ssboSize, ssboDecl, globalDecl, mainCode,
1594			makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1595					   OffsetValue(4,  4, makeValueUint32(1u)),
1596					   OffsetValue(4,  8, makeValueUint32(3u)),
1597					   OffsetValue(4, 12, makeValueUint32(3u))),
1598			(FeatureFlags)0,
1599			false,
1600		},
1601		{
1602			"xy",
1603			makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(6u)),
1604					   SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(4u))),
1605			ssboSize, ssboDecl, globalDecl, mainCode,
1606			makeVector(OffsetValue(4,  0, makeValueUint32(6u)),
1607					   OffsetValue(4,  4, makeValueUint32(4u)),
1608					   OffsetValue(4,  8, makeValueUint32(1u)),
1609					   OffsetValue(4, 12, makeValueUint32(6u * 4u))),
1610			(FeatureFlags)0,
1611			false,
1612		},
1613		{
1614			"xz",
1615			makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
1616					   SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(9u))),
1617			ssboSize, ssboDecl, globalDecl, mainCode,
1618			makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
1619					   OffsetValue(4,  4, makeValueUint32(1u)),
1620					   OffsetValue(4,  8, makeValueUint32(9u)),
1621					   OffsetValue(4, 12, makeValueUint32(3u * 9u))),
1622			(FeatureFlags)0,
1623			false,
1624		},
1625		{
1626			"yz",
1627			makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(2u)),
1628					   SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(5u))),
1629			ssboSize, ssboDecl, globalDecl, mainCode,
1630			makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1631					   OffsetValue(4,  4, makeValueUint32(2u)),
1632					   OffsetValue(4,  8, makeValueUint32(5u)),
1633					   OffsetValue(4, 12, makeValueUint32(2u * 5u))),
1634			(FeatureFlags)0,
1635			false,
1636		},
1637		{
1638			"xyz",
1639			makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
1640					   SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u)),
1641					   SpecConstant(3u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(7u))),
1642			ssboSize, ssboDecl, globalDecl, mainCode,
1643			makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
1644					   OffsetValue(4,  4, makeValueUint32(5u)),
1645					   OffsetValue(4,  8, makeValueUint32(7u)),
1646					   OffsetValue(4, 12, makeValueUint32(3u * 5u * 7u))),
1647			(FeatureFlags)0,
1648			false,
1649		},
1650	};
1651
1652	for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1653		testGroup->addChild(new SpecConstantTest(testCtx, PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC, VK_SHADER_STAGE_COMPUTE_BIT, defs[defNdx]));
1654
1655	return testGroup.release();
1656}
1657
1658//! Override a built-in variable with specialization constant value.
1659tcu::TestCaseGroup* createBuiltInOverrideTests (tcu::TestContext& testCtx, const PipelineConstructionType pipelineType, const VkShaderStageFlagBits shaderStage)
1660{
1661	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "builtin", "built-in override"));
1662
1663	const CaseDefinition defs[] =
1664	{
1665		{
1666			"default",
1667			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;")),
1668			4,
1669			"    bool ok;\n",
1670			"",
1671			"    sb_out.ok = (gl_MaxImageUnits >= 8);\n",	// implementation defined, 8 is the minimum
1672			makeVector(OffsetValue(4,  0, makeValueBool32(true))),
1673			(FeatureFlags)0,
1674			false,
1675		},
1676		{
1677			"specialized",
1678			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;", 4, makeValueInt32(12))),
1679			4,
1680			"    int maxImageUnits;\n",
1681			"",
1682			"    sb_out.maxImageUnits = gl_MaxImageUnits;\n",
1683			makeVector(OffsetValue(4,  0, makeValueInt32(12))),
1684			(FeatureFlags)0,
1685			false,
1686		},
1687	};
1688
1689	for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1690		testGroup->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, defs[defNdx]));
1691
1692	return testGroup.release();
1693}
1694
1695//! Specialization constants used in expressions.
1696tcu::TestCaseGroup* createExpressionTests (tcu::TestContext& testCtx, const PipelineConstructionType pipelineType, const VkShaderStageFlagBits shaderStage)
1697{
1698	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "expression", "specialization constants usage in expressions"));
1699
1700	const CaseDefinition defs[] =
1701	{
1702		{
1703			"spec_const_expression",
1704			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 2;"),
1705					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 3;", 4, makeValueInt32(5))),
1706			4,
1707			"    int result;\n",
1708
1709			"const int expr0 = sc0 + 1;\n"
1710			"const int expr1 = sc0 + sc1;\n",
1711
1712			"    sb_out.result = expr0 + expr1;\n",
1713			makeVector(OffsetValue(4,  0, makeValueInt32(10))),
1714			(FeatureFlags)0,
1715			false,
1716		},
1717		{
1718			"array_size",
1719			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1720					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(3))),
1721			16,
1722			"    int r0;\n"
1723			"    int r1[3];\n",
1724
1725			"",
1726
1727			"    int a0[sc0];\n"
1728			"    int a1[sc1];\n"
1729			"\n"
1730			"    for (int i = 0; i < sc0; ++i)\n"
1731			"        a0[i] = sc0 - i;\n"
1732			"    for (int i = 0; i < sc1; ++i)\n"
1733			"        a1[i] = sc1 - i;\n"
1734			"\n"
1735			"    sb_out.r0 = a0[0];\n"
1736			"    for (int i = 0; i < sc1; ++i)\n"
1737			"	     sb_out.r1[i] = a1[i];\n",
1738			makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1739					   OffsetValue(4,  4, makeValueInt32(3)),
1740					   OffsetValue(4,  8, makeValueInt32(2)),
1741					   OffsetValue(4, 12, makeValueInt32(1))),
1742			(FeatureFlags)0,
1743			false,
1744		},
1745		{
1746			"array_size_expression",
1747			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1748					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1749			8,
1750			"    int r0;\n"
1751			"    int r1;\n",
1752
1753			"",
1754
1755			"    int a0[sc0 + 3];\n"
1756			"    int a1[sc0 + sc1];\n"
1757			"\n"
1758			"    const int size0 = sc0 + 3;\n"
1759			"    const int size1 = sc0 + sc1;\n"
1760			"\n"
1761			"    for (int i = 0; i < size0; ++i)\n"
1762			"        a0[i] = 3 - i;\n"
1763			"    for (int i = 0; i < size1; ++i)\n"
1764			"        a1[i] = 5 - i;\n"
1765			"\n"
1766			"    sb_out.r0 = a0[size0 - 1];\n"
1767			"    sb_out.r1 = a1[size1 - 1];\n",
1768			makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1769					   OffsetValue(4,  4, makeValueInt32(-4))),
1770			(FeatureFlags)0,
1771			false,
1772		},
1773		{
1774			"array_size_spec_const_expression",
1775			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1776					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1777			8,
1778			"    int r0;\n"
1779			"    int r1;\n",
1780
1781			"",
1782
1783			"    const int size0 = sc0 + 3;\n"
1784			"    const int size1 = sc0 + sc1;\n"
1785			"\n"
1786			"    int a0[size0];\n"
1787			"    int a1[size1];\n"
1788			"\n"
1789			"    for (int i = 0; i < size0; ++i)\n"
1790			"        a0[i] = 3 - i;\n"
1791			"    for (int i = 0; i < size1; ++i)\n"
1792			"        a1[i] = 5 - i;\n"
1793			"\n"
1794			"    sb_out.r0 = a0[size0 - 1];\n"
1795			"    sb_out.r1 = a1[size1 - 1];\n",
1796			makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1797					   OffsetValue(4,  4, makeValueInt32(-4))),
1798			(FeatureFlags)0,
1799			false,
1800		},
1801		{
1802			"array_size_length",
1803			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1804					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(4))),
1805			8,
1806			"    int r0;\n"
1807			"    int r1;\n",
1808
1809			"",
1810
1811			"    int a0[sc0];\n"
1812			"    int a1[sc1];\n"
1813			"\n"
1814			"    sb_out.r0 = a0.length();\n"
1815			"    sb_out.r1 = a1.length();\n",
1816			makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1817					   OffsetValue(4,  4, makeValueInt32(4))),
1818			(FeatureFlags)0,
1819			false,
1820		},
1821		{
1822			"array_size_pass_to_function",
1823			makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1824					   SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 1;", 4, makeValueInt32(3))),
1825			4,
1826			"    int result;\n",
1827
1828			"int sumArrays (int a0[sc0], int a1[sc1])\n"
1829			"{\n"
1830			"    int sum = 0;\n"
1831			"    for (int i = 0; (i < sc0) && (i < sc1); ++i)\n"
1832			"        sum += a0[i] + a1[i];\n"
1833			"    return sum;\n"
1834			"}\n",
1835
1836			"    int a0[sc0];\n"
1837			"    int a1[sc1];\n"
1838			"\n"
1839			"    for (int i = 0; i < sc0; ++i)\n"
1840			"        a0[i] = i + 1;\n"
1841			"    for (int i = 0; i < sc1; ++i)\n"
1842			"        a1[i] = i + 2;\n"
1843			"\n"
1844			"    sb_out.result = sumArrays(a0, a1);\n",
1845			makeVector(OffsetValue(4,  0, makeValueInt32(15))),
1846			(FeatureFlags)0,
1847			false,
1848		},
1849	};
1850
1851	for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1852		testGroup->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, defs[defNdx]));
1853
1854	return testGroup.release();
1855}
1856
1857//! Helper functions internal to make*CompositeCaseDefinition functions.
1858namespace composite_case_internal
1859{
1860
1861//! Generate a string like this: "1, 2, sc0, 4" or "true, true, sc0"
1862//! castToType = true is useful when type requires more initializer values than we are providing, e.g.:
1863//!    vec2(1), vec2(sc0), vec(3)
1864std::string generateInitializerListWithSpecConstant (const glu::DataType	type,
1865													 const bool				castToType,
1866													 const int				idxBegin,
1867													 const int				idxEnd,
1868													 const std::string&		specConstName,
1869													 const int				specConstNdx)
1870{
1871	std::ostringstream str;
1872
1873	for (int i = idxBegin; i < idxEnd; ++i)
1874	{
1875		const std::string iVal = (i == specConstNdx ? specConstName : glu::getDataTypeScalarType(type) == glu::TYPE_BOOL ? "true" : de::toString(i + 1));
1876		str << (i != idxBegin ? ", " : "") << (castToType ? de::toString(glu::getDataTypeName(type)) + "(" + iVal + ")" : iVal);
1877	}
1878
1879	return str.str();
1880}
1881
1882std::string generateArrayConstructorString (const glu::DataType	elemType,
1883											const int			size1,
1884											const int			size2,
1885											const std::string&	specConstName,
1886											const int			specConstNdx)
1887{
1888	const bool isArrayOfArray = (size2 > 0);
1889	const bool doCast		  = (!isDataTypeScalar(elemType));
1890
1891	std::ostringstream arrayCtorExpr;
1892
1893	if (isArrayOfArray)
1894	{
1895		const std::string padding  (36, ' ');
1896		int               idxBegin = 0;
1897		int               idxEnd   = size2;
1898
1899		for (int iterNdx = 0; iterNdx < size1; ++iterNdx)
1900		{
1901			// Open sub-array ctor
1902			arrayCtorExpr << (iterNdx != 0 ? ",\n" + padding : "") << glu::getDataTypeName(elemType) << "[" << size2 << "](";
1903
1904			// Sub-array constructor elements
1905			arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, idxBegin, idxEnd, specConstName, specConstNdx);
1906
1907			// Close sub-array ctor, move to next range
1908			arrayCtorExpr << ")";
1909
1910			idxBegin += size2;
1911			idxEnd += size2;
1912		}
1913	}
1914	else
1915	{
1916		// Array constructor elements
1917		arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, 0, size1, specConstName, specConstNdx);
1918	}
1919
1920	return arrayCtorExpr.str();
1921}
1922
1923inline GenericValue makeValue (const glu::DataType type, const int specValue)
1924{
1925	if (type == glu::TYPE_DOUBLE)
1926		return makeValueFloat64(static_cast<double>(specValue));
1927	else if (type == glu::TYPE_FLOAT)
1928		return makeValueFloat32(static_cast<float>(specValue));
1929	else
1930		return makeValueInt32(specValue);
1931}
1932
1933deUint32 getDataTypeScalarSizeBytes (const glu::DataType dataType)
1934{
1935	switch (getDataTypeScalarType(dataType))
1936	{
1937		case glu::TYPE_FLOAT:
1938		case glu::TYPE_INT:
1939		case glu::TYPE_UINT:
1940		case glu::TYPE_BOOL:
1941			return 4;
1942
1943		case glu::TYPE_DOUBLE:
1944			return 8;
1945
1946		default:
1947			DE_ASSERT(false);
1948			return 0;
1949	}
1950}
1951
1952//! This applies to matrices/vectors/array cases. dataType must be a basic type.
1953std::vector<OffsetValue> computeExpectedValues (const int specValue, const glu::DataType dataType, const int numCombinations)
1954{
1955	DE_ASSERT(glu::isDataTypeScalar(dataType));
1956
1957	std::vector<OffsetValue> expectedValues;
1958
1959	for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1960	{
1961		int sum = 0;
1962		for (int i = 0; i < numCombinations; ++i)
1963			sum += (i == combNdx ? specValue : dataType == glu::TYPE_BOOL ? 1 : (i + 1));
1964
1965		const int dataSize = getDataTypeScalarSizeBytes(dataType);
1966		expectedValues.push_back(OffsetValue(dataSize, dataSize * combNdx, makeValue(dataType, sum)));
1967	}
1968
1969	return expectedValues;
1970}
1971
1972inline std::string getFirstDataElementSubscriptString (const glu::DataType type)
1973{
1974	// Grab the first element of a matrix/vector, if dealing with non-basic types.
1975	return (isDataTypeMatrix(type) ? "[0][0]" : isDataTypeVector(type) ? "[0]" : "");
1976}
1977
1978//! This code will go into the main function.
1979std::string generateShaderChecksumComputationCode (const glu::DataType	elemType,
1980												   const std::string&	varName,
1981												   const std::string&	accumType,
1982												   const int			size1,
1983												   const int			size2,
1984												   const int			numCombinations)
1985{
1986	std::ostringstream mainCode;
1987
1988	// Generate main code to calculate checksums for each array
1989	for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1990		mainCode << "    "<< accumType << " sum_" << varName << combNdx << " = " << accumType << "(0);\n";
1991
1992	if (size2 > 0)
1993	{
1994		mainCode << "\n"
1995					<< "    for (int i = 0; i < " << size1 << "; ++i)\n"
1996					<< "    for (int j = 0; j < " << size2 << "; ++j)\n"
1997					<< "    {\n";
1998
1999		for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
2000			mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
2001					 << varName << combNdx << "[i][j]" << getFirstDataElementSubscriptString(elemType) << ");\n";
2002	}
2003	else
2004	{
2005		mainCode << "\n"
2006					<< "    for (int i = 0; i < " << size1 << "; ++i)\n"
2007					<< "    {\n";
2008
2009		for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
2010			mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
2011					 << varName << combNdx << "[i]" << getFirstDataElementSubscriptString(elemType) << ");\n";
2012	}
2013
2014	mainCode << "    }\n"
2015				<< "\n";
2016
2017	for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
2018		mainCode << "    sb_out.result[" << combNdx << "] = sum_" << varName << combNdx << ";\n";
2019
2020	return mainCode.str();
2021}
2022
2023SpecConstant makeSpecConstant (const std::string specConstName, const deUint32 specConstId, const glu::DataType type, const int specValue)
2024{
2025	DE_ASSERT(glu::isDataTypeScalar(type));
2026
2027	const std::string typeName(glu::getDataTypeName(type));
2028
2029	return SpecConstant(
2030		specConstId,
2031		"layout(constant_id = ${ID}) const " + typeName + " " + specConstName + " = " + typeName + "(1);",
2032		getDataTypeScalarSizeBytes(type), makeValue(type, specValue));
2033}
2034
2035} // composite_case_internal ns
2036
2037//! Generate a CaseDefinition for a composite test using a matrix or vector (a 1-column matrix)
2038CaseDefinition makeMatrixVectorCompositeCaseDefinition (const glu::DataType type)
2039{
2040	using namespace composite_case_internal;
2041
2042	DE_ASSERT(!glu::isDataTypeScalar(type));
2043
2044	const std::string   varName         = (glu::isDataTypeMatrix(type) ? "m" : "v");
2045	const int           numCombinations = getDataTypeScalarSize(type);
2046	const glu::DataType scalarType      = glu::getDataTypeScalarType(type);
2047	const std::string   typeName        = glu::getDataTypeName(type);
2048	const bool			isConst		= (scalarType != glu::TYPE_FLOAT) && (scalarType != glu::TYPE_DOUBLE);
2049
2050	std::ostringstream globalCode;
2051	{
2052		// Build N matrices/vectors with specialization constant inserted at various locations in the constructor.
2053		for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
2054			globalCode << ( isConst ? "const " : "" ) << typeName << " " << varName << combNdx << " = " << typeName << "("
2055					   << generateInitializerListWithSpecConstant(type, false, 0, numCombinations, "sc0", combNdx) << ");\n";
2056	}
2057
2058	const bool        isBoolElement = (scalarType == glu::TYPE_BOOL);
2059	const int         specValue     = (isBoolElement ? 0 : 42);
2060	const std::string accumType     = glu::getDataTypeName(isBoolElement ? glu::TYPE_INT : scalarType);
2061
2062	const int size1 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : glu::getDataTypeNumComponents(type);
2063	const int size2 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumRows(type)    : 0;
2064
2065	const CaseDefinition def =
2066	{
2067		typeName,
2068		makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
2069		static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(type) * numCombinations),
2070		"    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
2071		globalCode.str(),
2072		generateShaderChecksumComputationCode(scalarType, varName, accumType, size1, size2, numCombinations),
2073		computeExpectedValues(specValue, scalarType, numCombinations),
2074		(scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
2075		false,
2076	};
2077	return def;
2078}
2079
2080//! Generate a CaseDefinition for a composite test using an array, or an array of array.
2081//! If (size1, size2) = (N, 0) -> type array[N]
2082//!                   = (N, M) -> type array[N][M]
2083CaseDefinition makeArrayCompositeCaseDefinition (const glu::DataType elemType, const int size1, const int size2 = 0)
2084{
2085	using namespace composite_case_internal;
2086
2087	DE_ASSERT(size1 > 0);
2088
2089	const bool        isArrayOfArray  = (size2 > 0);
2090	const std::string varName		  = "a";
2091	const std::string arraySizeDecl   = "[" + de::toString(size1) + "]" + (isArrayOfArray ? "[" + de::toString(size2) + "]" : "");
2092	const int         numCombinations = (isArrayOfArray ? size1 * size2 : size1);
2093	const std::string elemTypeName    (glu::getDataTypeName(elemType));
2094
2095	std::ostringstream globalCode;
2096	{
2097		// Create several arrays with specialization constant inserted in different positions.
2098		for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
2099			globalCode << elemTypeName << " " << varName << combNdx << arraySizeDecl << " = "
2100					   << elemTypeName << arraySizeDecl << "(" << generateArrayConstructorString(elemType, size1, size2, "sc0", combNdx) << ");\n";
2101	}
2102
2103	const glu::DataType scalarType = glu::getDataTypeScalarType(elemType);
2104	const bool          isBoolData = (scalarType == glu::TYPE_BOOL);
2105	const int           specValue  = (isBoolData ? 0 : 19);
2106	const std::string   caseName   = (isArrayOfArray ? "array_" : "") + elemTypeName;
2107	const std::string   accumType  = (glu::getDataTypeName(isBoolData ? glu::TYPE_INT : scalarType));
2108
2109	const CaseDefinition def =
2110	{
2111		caseName,
2112		makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
2113		static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(elemType) * numCombinations),
2114		"    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
2115		globalCode.str(),
2116		generateShaderChecksumComputationCode(elemType, varName, accumType, size1, size2, numCombinations),
2117		computeExpectedValues(specValue, scalarType, numCombinations),
2118		(scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
2119		false,
2120	};
2121	return def;
2122}
2123
2124//! A basic struct case, where one member is a specialization constant, or a specialization constant composite
2125//! (a matrix/vector with a spec. const. element).
2126CaseDefinition makeStructCompositeCaseDefinition (const glu::DataType memberType)
2127{
2128	using namespace composite_case_internal;
2129
2130	std::ostringstream globalCode;
2131	{
2132		globalCode << "struct Data {\n"
2133				   << "    int   i;\n"
2134				   << "    float f;\n"
2135				   << "    bool  b;\n"
2136				   << "    " << glu::getDataTypeName(memberType) << " sc;\n"
2137				   << "    uint  ui;\n"
2138				   << "};\n"
2139				   << "\n"
2140				   << "Data s0 = Data(3, 2.0, true, " << glu::getDataTypeName(memberType) << "(sc0), 8u);\n";
2141	}
2142
2143	const glu::DataType scalarType   = glu::getDataTypeScalarType(memberType);
2144	const bool          isBoolData   = (scalarType == glu::TYPE_BOOL);
2145	const int           specValue    = (isBoolData ? 0 : 23);
2146	const int           checksum     = (3 + 2 + 1 + specValue + 8);  // matches the shader code
2147	const glu::DataType accumType    = (isBoolData ? glu::TYPE_INT : scalarType);
2148	const std::string   accumTypeStr = glu::getDataTypeName(accumType);
2149
2150	std::ostringstream mainCode;
2151	{
2152		mainCode << "    " << accumTypeStr << " sum_s0 = " << accumTypeStr << "(0);\n"
2153				 << "\n"
2154				 << "    sum_s0 += " << accumTypeStr << "(s0.i);\n"
2155				 << "    sum_s0 += " << accumTypeStr << "(s0.f);\n"
2156				 << "    sum_s0 += " << accumTypeStr << "(s0.b);\n"
2157				 << "    sum_s0 += " << accumTypeStr << "(s0.sc" << getFirstDataElementSubscriptString(memberType) << ");\n"
2158				 << "    sum_s0 += " << accumTypeStr << "(s0.ui);\n"
2159				 << "\n"
2160				 << "    sb_out.result = sum_s0;\n";
2161	}
2162
2163	const std::string caseName = glu::getDataTypeName(memberType);
2164
2165	const CaseDefinition def =
2166	{
2167		caseName,
2168		makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
2169		getDataTypeScalarSizeBytes(accumType),
2170		"    " + accumTypeStr + " result;\n",
2171		globalCode.str(),
2172		mainCode.str(),
2173		makeVector(OffsetValue(getDataTypeScalarSizeBytes(memberType), 0, makeValue(scalarType, checksum))),
2174		(scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
2175		false,
2176	};
2177	return def;
2178}
2179
2180//! Specialization constants used in composites.
2181tcu::TestCaseGroup* createCompositeTests (tcu::TestContext& testCtx, const PipelineConstructionType pipelineType, const VkShaderStageFlagBits shaderStage)
2182{
2183	de::MovePtr<tcu::TestCaseGroup> compositeTests (new tcu::TestCaseGroup(testCtx, "composite", "specialization constants usage in composite types"));
2184
2185	// Vectors
2186	{
2187		de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "vector"));
2188
2189		const glu::DataType types[] =
2190		{
2191			glu::TYPE_FLOAT_VEC2,
2192			glu::TYPE_FLOAT_VEC3,
2193			glu::TYPE_FLOAT_VEC4,
2194
2195			glu::TYPE_DOUBLE_VEC2,
2196			glu::TYPE_DOUBLE_VEC3,
2197			glu::TYPE_DOUBLE_VEC4,
2198
2199			glu::TYPE_BOOL_VEC2,
2200			glu::TYPE_BOOL_VEC3,
2201			glu::TYPE_BOOL_VEC4,
2202
2203			glu::TYPE_INT_VEC2,
2204			glu::TYPE_INT_VEC3,
2205			glu::TYPE_INT_VEC4,
2206
2207			glu::TYPE_UINT_VEC2,
2208			glu::TYPE_UINT_VEC3,
2209			glu::TYPE_UINT_VEC4,
2210		};
2211		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
2212			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
2213
2214		compositeTests->addChild(group.release());
2215	}
2216
2217	// Matrices
2218	{
2219		de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "matrix"));
2220
2221		const glu::DataType types[] =
2222		{
2223			glu::TYPE_FLOAT_MAT2,
2224			glu::TYPE_FLOAT_MAT2X3,
2225			glu::TYPE_FLOAT_MAT2X4,
2226			glu::TYPE_FLOAT_MAT3X2,
2227			glu::TYPE_FLOAT_MAT3,
2228			glu::TYPE_FLOAT_MAT3X4,
2229			glu::TYPE_FLOAT_MAT4X2,
2230			glu::TYPE_FLOAT_MAT4X3,
2231			glu::TYPE_FLOAT_MAT4,
2232
2233			glu::TYPE_DOUBLE_MAT2,
2234			glu::TYPE_DOUBLE_MAT2X3,
2235			glu::TYPE_DOUBLE_MAT2X4,
2236			glu::TYPE_DOUBLE_MAT3X2,
2237			glu::TYPE_DOUBLE_MAT3,
2238			glu::TYPE_DOUBLE_MAT3X4,
2239			glu::TYPE_DOUBLE_MAT4X2,
2240			glu::TYPE_DOUBLE_MAT4X3,
2241			glu::TYPE_DOUBLE_MAT4,
2242		};
2243		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
2244			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
2245
2246		compositeTests->addChild(group.release());
2247	}
2248
2249	const glu::DataType allTypes[] =
2250	{
2251		glu::TYPE_FLOAT,
2252		glu::TYPE_FLOAT_VEC2,
2253		glu::TYPE_FLOAT_VEC3,
2254		glu::TYPE_FLOAT_VEC4,
2255		glu::TYPE_FLOAT_MAT2,
2256		glu::TYPE_FLOAT_MAT2X3,
2257		glu::TYPE_FLOAT_MAT2X4,
2258		glu::TYPE_FLOAT_MAT3X2,
2259		glu::TYPE_FLOAT_MAT3,
2260		glu::TYPE_FLOAT_MAT3X4,
2261		glu::TYPE_FLOAT_MAT4X2,
2262		glu::TYPE_FLOAT_MAT4X3,
2263		glu::TYPE_FLOAT_MAT4,
2264
2265		glu::TYPE_DOUBLE,
2266		glu::TYPE_DOUBLE_VEC2,
2267		glu::TYPE_DOUBLE_VEC3,
2268		glu::TYPE_DOUBLE_VEC4,
2269		glu::TYPE_DOUBLE_MAT2,
2270		glu::TYPE_DOUBLE_MAT2X3,
2271		glu::TYPE_DOUBLE_MAT2X4,
2272		glu::TYPE_DOUBLE_MAT3X2,
2273		glu::TYPE_DOUBLE_MAT3,
2274		glu::TYPE_DOUBLE_MAT3X4,
2275		glu::TYPE_DOUBLE_MAT4X2,
2276		glu::TYPE_DOUBLE_MAT4X3,
2277		glu::TYPE_DOUBLE_MAT4,
2278
2279		glu::TYPE_INT,
2280		glu::TYPE_INT_VEC2,
2281		glu::TYPE_INT_VEC3,
2282		glu::TYPE_INT_VEC4,
2283
2284		glu::TYPE_UINT,
2285		glu::TYPE_UINT_VEC2,
2286		glu::TYPE_UINT_VEC3,
2287		glu::TYPE_UINT_VEC4,
2288
2289		glu::TYPE_BOOL,
2290		glu::TYPE_BOOL_VEC2,
2291		glu::TYPE_BOOL_VEC3,
2292		glu::TYPE_BOOL_VEC4,
2293	};
2294
2295	// Array cases
2296	{
2297		de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "array"));
2298
2299		// Array of T
2300		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2301			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3)));
2302
2303		// Array of array of T
2304		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2305			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3, 2)));
2306
2307		// Special case - array of struct
2308		{
2309			const int checksum = (3 + 2 + 1) + (1 + 5 + 1) + (1 + 2 + 0);
2310			const CaseDefinition def =
2311			{
2312				"struct",
2313				makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int   sc0 = 1;",    4, makeValueInt32  (3)),
2314						   SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.0;",  4, makeValueFloat32(5.0f)),
2315						   SpecConstant(3u, "layout(constant_id = ${ID}) const bool  sc2 = true;", 4, makeValueBool32 (false))),
2316				4,
2317				"    int result;\n",
2318
2319				"struct Data {\n"
2320				"    int   x;\n"
2321				"    float y;\n"
2322				"    bool  z;\n"
2323				"};\n"
2324				"\n"
2325				"Data a0[3] = Data[3](Data(sc0, 2.0, true), Data(1, sc1, true), Data(1, 2.0, sc2));\n",
2326
2327				"    int sum_a0 = 0;\n"
2328				"\n"
2329				"    for (int i = 0; i < 3; ++i)\n"
2330				"        sum_a0 += int(a0[i].x) + int(a0[i].y) + int(a0[i].z);\n"
2331				"\n"
2332				"    sb_out.result = sum_a0;\n",
2333
2334				makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
2335				(FeatureFlags)0,
2336				false,
2337			};
2338
2339			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, def));
2340		}
2341
2342		compositeTests->addChild(group.release());
2343	}
2344
2345	// Struct cases
2346	{
2347		de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "struct"));
2348
2349		// Struct with one member being a specialization constant (or spec. const. composite) of a given type
2350		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2351			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, makeStructCompositeCaseDefinition(allTypes[typeNdx])));
2352
2353		// Special case - struct with array
2354		{
2355			const int checksum = (1 + 2 + 31 + 4 + 0);
2356			const CaseDefinition def =
2357			{
2358				"array",
2359				makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 1.0;",  4, makeValueFloat32(31.0f))),
2360				4,
2361				"    float result;\n",
2362
2363				"struct Data {\n"
2364				"    int  i;\n"
2365				"    vec3 sc[3];\n"
2366				"    bool b;\n"
2367				"};\n"
2368				"\n"
2369				"Data s0 = Data(1, vec3[3](vec3(2.0), vec3(sc0), vec3(4.0)), false);\n",
2370
2371				"    float sum_s0 = 0;\n"
2372				"\n"
2373				"    sum_s0 += float(s0.i);\n"
2374				"    sum_s0 += float(s0.sc[0][0]);\n"
2375				"    sum_s0 += float(s0.sc[1][0]);\n"
2376				"    sum_s0 += float(s0.sc[2][0]);\n"
2377				"    sum_s0 += float(s0.b);\n"
2378				"\n"
2379				"    sb_out.result = sum_s0;\n",
2380
2381				makeVector(OffsetValue(4,  0, makeValueFloat32(static_cast<float>(checksum)))),
2382				(FeatureFlags)0,
2383				false,
2384			};
2385
2386			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, def));
2387		}
2388
2389		// Special case - struct of struct
2390		{
2391			const int checksum = (1 + 2 + 11 + 4 + 1);
2392			const CaseDefinition def =
2393			{
2394				"struct",
2395				makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;",  4, makeValueInt32(11))),
2396				4,
2397				"    int result;\n",
2398
2399				"struct Nested {\n"
2400				"    vec2  v;\n"
2401				"    int   sc;\n"
2402				"    float f;\n"
2403				"};\n"
2404				"\n"
2405				"struct Data {\n"
2406				"    uint   ui;\n"
2407				"    Nested s;\n"
2408				"    bool   b;\n"
2409				"};\n"
2410				"\n"
2411				"Data s0 = Data(1u, Nested(vec2(2.0), sc0, 4.0), true);\n",
2412
2413				"    int sum_s0 = 0;\n"
2414				"\n"
2415				"    sum_s0 += int(s0.ui);\n"
2416				"    sum_s0 += int(s0.s.v[0]);\n"
2417				"    sum_s0 += int(s0.s.sc);\n"
2418				"    sum_s0 += int(s0.s.f);\n"
2419				"    sum_s0 += int(s0.b);\n"
2420				"\n"
2421				"    sb_out.result = sum_s0;\n",
2422
2423				makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
2424				(FeatureFlags)0,
2425				false,
2426			};
2427
2428			group->addChild(new SpecConstantTest(testCtx, pipelineType, shaderStage, def));
2429		}
2430
2431		compositeTests->addChild(group.release());
2432	}
2433
2434	return compositeTests.release();
2435}
2436
2437} // anonymous ns
2438
2439tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineType)
2440{
2441	de::MovePtr<tcu::TestCaseGroup> allTests (new tcu::TestCaseGroup(testCtx, "spec_constant", "Specialization constants tests"));
2442	de::MovePtr<tcu::TestCaseGroup> graphicsGroup (new tcu::TestCaseGroup(testCtx, "graphics"));
2443
2444	struct StageDef
2445	{
2446		tcu::TestCaseGroup*		parentGroup;
2447		const char*				name;
2448		VkShaderStageFlagBits	stage;
2449	};
2450
2451	const StageDef stages[] =
2452	{
2453		{ graphicsGroup.get(),	"vertex",		VK_SHADER_STAGE_VERTEX_BIT					},
2454		{ graphicsGroup.get(),	"fragment",		VK_SHADER_STAGE_FRAGMENT_BIT				},
2455		{ graphicsGroup.get(),	"tess_control",	VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT	},
2456		{ graphicsGroup.get(),	"tess_eval",	VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT	},
2457		{ graphicsGroup.get(),	"geometry",		VK_SHADER_STAGE_GEOMETRY_BIT				},
2458		{ allTests.get(),		"compute",		VK_SHADER_STAGE_COMPUTE_BIT					},
2459	};
2460
2461	allTests->addChild(graphicsGroup.release());
2462
2463	for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx)
2464	{
2465		const StageDef&		stage		= stages[stageNdx];
2466		const bool			isCompute	= (stage.stage == VK_SHADER_STAGE_COMPUTE_BIT);
2467
2468		if (isCompute && (pipelineType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC))
2469			continue;
2470
2471		de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, stage.name));
2472
2473		stageGroup->addChild(createDefaultValueTests		(testCtx, pipelineType, stage.stage));
2474		stageGroup->addChild(createBasicSpecializationTests	(testCtx, pipelineType, stage.stage));
2475		stageGroup->addChild(createBuiltInOverrideTests		(testCtx, pipelineType, stage.stage));
2476		stageGroup->addChild(createExpressionTests			(testCtx, pipelineType, stage.stage));
2477		stageGroup->addChild(createCompositeTests			(testCtx, pipelineType, stage.stage));
2478
2479		if (isCompute)
2480			stageGroup->addChild(createWorkGroupSizeTests(testCtx));
2481
2482		stage.parentGroup->addChild(stageGroup.release());
2483	}
2484
2485	return allTests.release();
2486}
2487
2488} // pipeline
2489} // vkt
2490