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