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