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