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