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